Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/Object/ArchiveWriter.cpp
35232 views
1
//===- ArchiveWriter.cpp - ar File Format implementation --------*- C++ -*-===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// This file defines the writeArchive function.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "llvm/Object/ArchiveWriter.h"
14
#include "llvm/ADT/ArrayRef.h"
15
#include "llvm/ADT/StringMap.h"
16
#include "llvm/ADT/StringRef.h"
17
#include "llvm/BinaryFormat/Magic.h"
18
#include "llvm/IR/LLVMContext.h"
19
#include "llvm/Object/Archive.h"
20
#include "llvm/Object/COFF.h"
21
#include "llvm/Object/COFFImportFile.h"
22
#include "llvm/Object/Error.h"
23
#include "llvm/Object/IRObjectFile.h"
24
#include "llvm/Object/MachO.h"
25
#include "llvm/Object/ObjectFile.h"
26
#include "llvm/Object/SymbolicFile.h"
27
#include "llvm/Object/XCOFFObjectFile.h"
28
#include "llvm/Support/Alignment.h"
29
#include "llvm/Support/EndianStream.h"
30
#include "llvm/Support/Errc.h"
31
#include "llvm/Support/ErrorHandling.h"
32
#include "llvm/Support/Format.h"
33
#include "llvm/Support/MathExtras.h"
34
#include "llvm/Support/Path.h"
35
#include "llvm/Support/SmallVectorMemoryBuffer.h"
36
#include "llvm/Support/raw_ostream.h"
37
38
#include <cerrno>
39
#include <map>
40
41
#if !defined(_MSC_VER) && !defined(__MINGW32__)
42
#include <unistd.h>
43
#else
44
#include <io.h>
45
#endif
46
47
using namespace llvm;
48
using namespace llvm::object;
49
50
struct SymMap {
51
bool UseECMap = false;
52
std::map<std::string, uint16_t> Map;
53
std::map<std::string, uint16_t> ECMap;
54
};
55
56
NewArchiveMember::NewArchiveMember(MemoryBufferRef BufRef)
57
: Buf(MemoryBuffer::getMemBuffer(BufRef, false)),
58
MemberName(BufRef.getBufferIdentifier()) {}
59
60
object::Archive::Kind NewArchiveMember::detectKindFromObject() const {
61
auto MemBufferRef = this->Buf->getMemBufferRef();
62
Expected<std::unique_ptr<object::ObjectFile>> OptionalObject =
63
object::ObjectFile::createObjectFile(MemBufferRef);
64
65
if (OptionalObject) {
66
if (isa<object::MachOObjectFile>(**OptionalObject))
67
return object::Archive::K_DARWIN;
68
if (isa<object::XCOFFObjectFile>(**OptionalObject))
69
return object::Archive::K_AIXBIG;
70
if (isa<object::COFFObjectFile>(**OptionalObject) ||
71
isa<object::COFFImportFile>(**OptionalObject))
72
return object::Archive::K_COFF;
73
return object::Archive::K_GNU;
74
}
75
76
// Squelch the error in case we had a non-object file.
77
consumeError(OptionalObject.takeError());
78
79
// If we're adding a bitcode file to the archive, detect the Archive kind
80
// based on the target triple.
81
LLVMContext Context;
82
if (identify_magic(MemBufferRef.getBuffer()) == file_magic::bitcode) {
83
if (auto ObjOrErr = object::SymbolicFile::createSymbolicFile(
84
MemBufferRef, file_magic::bitcode, &Context)) {
85
auto &IRObject = cast<object::IRObjectFile>(**ObjOrErr);
86
auto TargetTriple = Triple(IRObject.getTargetTriple());
87
return object::Archive::getDefaultKindForTriple(TargetTriple);
88
} else {
89
// Squelch the error in case this was not a SymbolicFile.
90
consumeError(ObjOrErr.takeError());
91
}
92
}
93
94
return object::Archive::getDefaultKind();
95
}
96
97
Expected<NewArchiveMember>
98
NewArchiveMember::getOldMember(const object::Archive::Child &OldMember,
99
bool Deterministic) {
100
Expected<llvm::MemoryBufferRef> BufOrErr = OldMember.getMemoryBufferRef();
101
if (!BufOrErr)
102
return BufOrErr.takeError();
103
104
NewArchiveMember M;
105
M.Buf = MemoryBuffer::getMemBuffer(*BufOrErr, false);
106
M.MemberName = M.Buf->getBufferIdentifier();
107
if (!Deterministic) {
108
auto ModTimeOrErr = OldMember.getLastModified();
109
if (!ModTimeOrErr)
110
return ModTimeOrErr.takeError();
111
M.ModTime = ModTimeOrErr.get();
112
Expected<unsigned> UIDOrErr = OldMember.getUID();
113
if (!UIDOrErr)
114
return UIDOrErr.takeError();
115
M.UID = UIDOrErr.get();
116
Expected<unsigned> GIDOrErr = OldMember.getGID();
117
if (!GIDOrErr)
118
return GIDOrErr.takeError();
119
M.GID = GIDOrErr.get();
120
Expected<sys::fs::perms> AccessModeOrErr = OldMember.getAccessMode();
121
if (!AccessModeOrErr)
122
return AccessModeOrErr.takeError();
123
M.Perms = AccessModeOrErr.get();
124
}
125
return std::move(M);
126
}
127
128
Expected<NewArchiveMember> NewArchiveMember::getFile(StringRef FileName,
129
bool Deterministic) {
130
sys::fs::file_status Status;
131
auto FDOrErr = sys::fs::openNativeFileForRead(FileName);
132
if (!FDOrErr)
133
return FDOrErr.takeError();
134
sys::fs::file_t FD = *FDOrErr;
135
assert(FD != sys::fs::kInvalidFile);
136
137
if (auto EC = sys::fs::status(FD, Status))
138
return errorCodeToError(EC);
139
140
// Opening a directory doesn't make sense. Let it fail.
141
// Linux cannot open directories with open(2), although
142
// cygwin and *bsd can.
143
if (Status.type() == sys::fs::file_type::directory_file)
144
return errorCodeToError(make_error_code(errc::is_a_directory));
145
146
ErrorOr<std::unique_ptr<MemoryBuffer>> MemberBufferOrErr =
147
MemoryBuffer::getOpenFile(FD, FileName, Status.getSize(), false);
148
if (!MemberBufferOrErr)
149
return errorCodeToError(MemberBufferOrErr.getError());
150
151
if (auto EC = sys::fs::closeFile(FD))
152
return errorCodeToError(EC);
153
154
NewArchiveMember M;
155
M.Buf = std::move(*MemberBufferOrErr);
156
M.MemberName = M.Buf->getBufferIdentifier();
157
if (!Deterministic) {
158
M.ModTime = std::chrono::time_point_cast<std::chrono::seconds>(
159
Status.getLastModificationTime());
160
M.UID = Status.getUser();
161
M.GID = Status.getGroup();
162
M.Perms = Status.permissions();
163
}
164
return std::move(M);
165
}
166
167
template <typename T>
168
static void printWithSpacePadding(raw_ostream &OS, T Data, unsigned Size) {
169
uint64_t OldPos = OS.tell();
170
OS << Data;
171
unsigned SizeSoFar = OS.tell() - OldPos;
172
assert(SizeSoFar <= Size && "Data doesn't fit in Size");
173
OS.indent(Size - SizeSoFar);
174
}
175
176
static bool isDarwin(object::Archive::Kind Kind) {
177
return Kind == object::Archive::K_DARWIN ||
178
Kind == object::Archive::K_DARWIN64;
179
}
180
181
static bool isAIXBigArchive(object::Archive::Kind Kind) {
182
return Kind == object::Archive::K_AIXBIG;
183
}
184
185
static bool isCOFFArchive(object::Archive::Kind Kind) {
186
return Kind == object::Archive::K_COFF;
187
}
188
189
static bool isBSDLike(object::Archive::Kind Kind) {
190
switch (Kind) {
191
case object::Archive::K_GNU:
192
case object::Archive::K_GNU64:
193
case object::Archive::K_AIXBIG:
194
case object::Archive::K_COFF:
195
return false;
196
case object::Archive::K_BSD:
197
case object::Archive::K_DARWIN:
198
case object::Archive::K_DARWIN64:
199
return true;
200
}
201
llvm_unreachable("not supported for writting");
202
}
203
204
template <class T>
205
static void print(raw_ostream &Out, object::Archive::Kind Kind, T Val) {
206
support::endian::write(Out, Val,
207
isBSDLike(Kind) ? llvm::endianness::little
208
: llvm::endianness::big);
209
}
210
211
template <class T> static void printLE(raw_ostream &Out, T Val) {
212
support::endian::write(Out, Val, llvm::endianness::little);
213
}
214
215
static void printRestOfMemberHeader(
216
raw_ostream &Out, const sys::TimePoint<std::chrono::seconds> &ModTime,
217
unsigned UID, unsigned GID, unsigned Perms, uint64_t Size) {
218
printWithSpacePadding(Out, sys::toTimeT(ModTime), 12);
219
220
// The format has only 6 chars for uid and gid. Truncate if the provided
221
// values don't fit.
222
printWithSpacePadding(Out, UID % 1000000, 6);
223
printWithSpacePadding(Out, GID % 1000000, 6);
224
225
printWithSpacePadding(Out, format("%o", Perms), 8);
226
printWithSpacePadding(Out, Size, 10);
227
Out << "`\n";
228
}
229
230
static void
231
printGNUSmallMemberHeader(raw_ostream &Out, StringRef Name,
232
const sys::TimePoint<std::chrono::seconds> &ModTime,
233
unsigned UID, unsigned GID, unsigned Perms,
234
uint64_t Size) {
235
printWithSpacePadding(Out, Twine(Name) + "/", 16);
236
printRestOfMemberHeader(Out, ModTime, UID, GID, Perms, Size);
237
}
238
239
static void
240
printBSDMemberHeader(raw_ostream &Out, uint64_t Pos, StringRef Name,
241
const sys::TimePoint<std::chrono::seconds> &ModTime,
242
unsigned UID, unsigned GID, unsigned Perms, uint64_t Size) {
243
uint64_t PosAfterHeader = Pos + 60 + Name.size();
244
// Pad so that even 64 bit object files are aligned.
245
unsigned Pad = offsetToAlignment(PosAfterHeader, Align(8));
246
unsigned NameWithPadding = Name.size() + Pad;
247
printWithSpacePadding(Out, Twine("#1/") + Twine(NameWithPadding), 16);
248
printRestOfMemberHeader(Out, ModTime, UID, GID, Perms,
249
NameWithPadding + Size);
250
Out << Name;
251
while (Pad--)
252
Out.write(uint8_t(0));
253
}
254
255
static void
256
printBigArchiveMemberHeader(raw_ostream &Out, StringRef Name,
257
const sys::TimePoint<std::chrono::seconds> &ModTime,
258
unsigned UID, unsigned GID, unsigned Perms,
259
uint64_t Size, uint64_t PrevOffset,
260
uint64_t NextOffset) {
261
unsigned NameLen = Name.size();
262
263
printWithSpacePadding(Out, Size, 20); // File member size
264
printWithSpacePadding(Out, NextOffset, 20); // Next member header offset
265
printWithSpacePadding(Out, PrevOffset, 20); // Previous member header offset
266
printWithSpacePadding(Out, sys::toTimeT(ModTime), 12); // File member date
267
// The big archive format has 12 chars for uid and gid.
268
printWithSpacePadding(Out, UID % 1000000000000, 12); // UID
269
printWithSpacePadding(Out, GID % 1000000000000, 12); // GID
270
printWithSpacePadding(Out, format("%o", Perms), 12); // Permission
271
printWithSpacePadding(Out, NameLen, 4); // Name length
272
if (NameLen) {
273
printWithSpacePadding(Out, Name, NameLen); // Name
274
if (NameLen % 2)
275
Out.write(uint8_t(0)); // Null byte padding
276
}
277
Out << "`\n"; // Terminator
278
}
279
280
static bool useStringTable(bool Thin, StringRef Name) {
281
return Thin || Name.size() >= 16 || Name.contains('/');
282
}
283
284
static bool is64BitKind(object::Archive::Kind Kind) {
285
switch (Kind) {
286
case object::Archive::K_GNU:
287
case object::Archive::K_BSD:
288
case object::Archive::K_DARWIN:
289
case object::Archive::K_COFF:
290
return false;
291
case object::Archive::K_AIXBIG:
292
case object::Archive::K_DARWIN64:
293
case object::Archive::K_GNU64:
294
return true;
295
}
296
llvm_unreachable("not supported for writting");
297
}
298
299
static void
300
printMemberHeader(raw_ostream &Out, uint64_t Pos, raw_ostream &StringTable,
301
StringMap<uint64_t> &MemberNames, object::Archive::Kind Kind,
302
bool Thin, const NewArchiveMember &M,
303
sys::TimePoint<std::chrono::seconds> ModTime, uint64_t Size) {
304
if (isBSDLike(Kind))
305
return printBSDMemberHeader(Out, Pos, M.MemberName, ModTime, M.UID, M.GID,
306
M.Perms, Size);
307
if (!useStringTable(Thin, M.MemberName))
308
return printGNUSmallMemberHeader(Out, M.MemberName, ModTime, M.UID, M.GID,
309
M.Perms, Size);
310
Out << '/';
311
uint64_t NamePos;
312
if (Thin) {
313
NamePos = StringTable.tell();
314
StringTable << M.MemberName << "/\n";
315
} else {
316
auto Insertion = MemberNames.insert({M.MemberName, uint64_t(0)});
317
if (Insertion.second) {
318
Insertion.first->second = StringTable.tell();
319
StringTable << M.MemberName;
320
if (isCOFFArchive(Kind))
321
StringTable << '\0';
322
else
323
StringTable << "/\n";
324
}
325
NamePos = Insertion.first->second;
326
}
327
printWithSpacePadding(Out, NamePos, 15);
328
printRestOfMemberHeader(Out, ModTime, M.UID, M.GID, M.Perms, Size);
329
}
330
331
namespace {
332
struct MemberData {
333
std::vector<unsigned> Symbols;
334
std::string Header;
335
StringRef Data;
336
StringRef Padding;
337
uint64_t PreHeadPadSize = 0;
338
std::unique_ptr<SymbolicFile> SymFile = nullptr;
339
};
340
} // namespace
341
342
static MemberData computeStringTable(StringRef Names) {
343
unsigned Size = Names.size();
344
unsigned Pad = offsetToAlignment(Size, Align(2));
345
std::string Header;
346
raw_string_ostream Out(Header);
347
printWithSpacePadding(Out, "//", 48);
348
printWithSpacePadding(Out, Size + Pad, 10);
349
Out << "`\n";
350
Out.flush();
351
return {{}, std::move(Header), Names, Pad ? "\n" : ""};
352
}
353
354
static sys::TimePoint<std::chrono::seconds> now(bool Deterministic) {
355
using namespace std::chrono;
356
357
if (!Deterministic)
358
return time_point_cast<seconds>(system_clock::now());
359
return sys::TimePoint<seconds>();
360
}
361
362
static bool isArchiveSymbol(const object::BasicSymbolRef &S) {
363
Expected<uint32_t> SymFlagsOrErr = S.getFlags();
364
if (!SymFlagsOrErr)
365
// TODO: Actually report errors helpfully.
366
report_fatal_error(SymFlagsOrErr.takeError());
367
if (*SymFlagsOrErr & object::SymbolRef::SF_FormatSpecific)
368
return false;
369
if (!(*SymFlagsOrErr & object::SymbolRef::SF_Global))
370
return false;
371
if (*SymFlagsOrErr & object::SymbolRef::SF_Undefined)
372
return false;
373
return true;
374
}
375
376
static void printNBits(raw_ostream &Out, object::Archive::Kind Kind,
377
uint64_t Val) {
378
if (is64BitKind(Kind))
379
print<uint64_t>(Out, Kind, Val);
380
else
381
print<uint32_t>(Out, Kind, Val);
382
}
383
384
static uint64_t computeSymbolTableSize(object::Archive::Kind Kind,
385
uint64_t NumSyms, uint64_t OffsetSize,
386
uint64_t StringTableSize,
387
uint32_t *Padding = nullptr) {
388
assert((OffsetSize == 4 || OffsetSize == 8) && "Unsupported OffsetSize");
389
uint64_t Size = OffsetSize; // Number of entries
390
if (isBSDLike(Kind))
391
Size += NumSyms * OffsetSize * 2; // Table
392
else
393
Size += NumSyms * OffsetSize; // Table
394
if (isBSDLike(Kind))
395
Size += OffsetSize; // byte count
396
Size += StringTableSize;
397
// ld64 expects the members to be 8-byte aligned for 64-bit content and at
398
// least 4-byte aligned for 32-bit content. Opt for the larger encoding
399
// uniformly.
400
// We do this for all bsd formats because it simplifies aligning members.
401
// For the big archive format, the symbol table is the last member, so there
402
// is no need to align.
403
uint32_t Pad = isAIXBigArchive(Kind)
404
? 0
405
: offsetToAlignment(Size, Align(isBSDLike(Kind) ? 8 : 2));
406
407
Size += Pad;
408
if (Padding)
409
*Padding = Pad;
410
return Size;
411
}
412
413
static uint64_t computeSymbolMapSize(uint64_t NumObj, SymMap &SymMap,
414
uint32_t *Padding = nullptr) {
415
uint64_t Size = sizeof(uint32_t) * 2; // Number of symbols and objects entries
416
Size += NumObj * sizeof(uint32_t); // Offset table
417
418
for (auto S : SymMap.Map)
419
Size += sizeof(uint16_t) + S.first.length() + 1;
420
421
uint32_t Pad = offsetToAlignment(Size, Align(2));
422
Size += Pad;
423
if (Padding)
424
*Padding = Pad;
425
return Size;
426
}
427
428
static uint64_t computeECSymbolsSize(SymMap &SymMap,
429
uint32_t *Padding = nullptr) {
430
uint64_t Size = sizeof(uint32_t); // Number of symbols
431
432
for (auto S : SymMap.ECMap)
433
Size += sizeof(uint16_t) + S.first.length() + 1;
434
435
uint32_t Pad = offsetToAlignment(Size, Align(2));
436
Size += Pad;
437
if (Padding)
438
*Padding = Pad;
439
return Size;
440
}
441
442
static void writeSymbolTableHeader(raw_ostream &Out, object::Archive::Kind Kind,
443
bool Deterministic, uint64_t Size,
444
uint64_t PrevMemberOffset = 0,
445
uint64_t NextMemberOffset = 0) {
446
if (isBSDLike(Kind)) {
447
const char *Name = is64BitKind(Kind) ? "__.SYMDEF_64" : "__.SYMDEF";
448
printBSDMemberHeader(Out, Out.tell(), Name, now(Deterministic), 0, 0, 0,
449
Size);
450
} else if (isAIXBigArchive(Kind)) {
451
printBigArchiveMemberHeader(Out, "", now(Deterministic), 0, 0, 0, Size,
452
PrevMemberOffset, NextMemberOffset);
453
} else {
454
const char *Name = is64BitKind(Kind) ? "/SYM64" : "";
455
printGNUSmallMemberHeader(Out, Name, now(Deterministic), 0, 0, 0, Size);
456
}
457
}
458
459
static uint64_t computeHeadersSize(object::Archive::Kind Kind,
460
uint64_t NumMembers,
461
uint64_t StringMemberSize, uint64_t NumSyms,
462
uint64_t SymNamesSize, SymMap *SymMap) {
463
uint32_t OffsetSize = is64BitKind(Kind) ? 8 : 4;
464
uint64_t SymtabSize =
465
computeSymbolTableSize(Kind, NumSyms, OffsetSize, SymNamesSize);
466
auto computeSymbolTableHeaderSize = [=] {
467
SmallString<0> TmpBuf;
468
raw_svector_ostream Tmp(TmpBuf);
469
writeSymbolTableHeader(Tmp, Kind, true, SymtabSize);
470
return TmpBuf.size();
471
};
472
uint32_t HeaderSize = computeSymbolTableHeaderSize();
473
uint64_t Size = strlen("!<arch>\n") + HeaderSize + SymtabSize;
474
475
if (SymMap) {
476
Size += HeaderSize + computeSymbolMapSize(NumMembers, *SymMap);
477
if (SymMap->ECMap.size())
478
Size += HeaderSize + computeECSymbolsSize(*SymMap);
479
}
480
481
return Size + StringMemberSize;
482
}
483
484
static Expected<std::unique_ptr<SymbolicFile>>
485
getSymbolicFile(MemoryBufferRef Buf, LLVMContext &Context,
486
object::Archive::Kind Kind, function_ref<void(Error)> Warn) {
487
const file_magic Type = identify_magic(Buf.getBuffer());
488
// Don't attempt to read non-symbolic file types.
489
if (!object::SymbolicFile::isSymbolicFile(Type, &Context))
490
return nullptr;
491
if (Type == file_magic::bitcode) {
492
auto ObjOrErr = object::SymbolicFile::createSymbolicFile(
493
Buf, file_magic::bitcode, &Context);
494
// An error reading a bitcode file most likely indicates that the file
495
// was created by a compiler from the future. Normally we don't try to
496
// implement forwards compatibility for bitcode files, but when creating an
497
// archive we can implement best-effort forwards compatibility by treating
498
// the file as a blob and not creating symbol index entries for it. lld and
499
// mold ignore the archive symbol index, so provided that you use one of
500
// these linkers, LTO will work as long as lld or the gold plugin is newer
501
// than the compiler. We only ignore errors if the archive format is one
502
// that is supported by a linker that is known to ignore the index,
503
// otherwise there's no chance of this working so we may as well error out.
504
// We print a warning on read failure so that users of linkers that rely on
505
// the symbol index can diagnose the issue.
506
//
507
// This is the same behavior as GNU ar when the linker plugin returns an
508
// error when reading the input file. If the bitcode file is actually
509
// malformed, it will be diagnosed at link time.
510
if (!ObjOrErr) {
511
switch (Kind) {
512
case object::Archive::K_BSD:
513
case object::Archive::K_GNU:
514
case object::Archive::K_GNU64:
515
Warn(ObjOrErr.takeError());
516
return nullptr;
517
case object::Archive::K_AIXBIG:
518
case object::Archive::K_COFF:
519
case object::Archive::K_DARWIN:
520
case object::Archive::K_DARWIN64:
521
return ObjOrErr.takeError();
522
}
523
}
524
return std::move(*ObjOrErr);
525
} else {
526
auto ObjOrErr = object::SymbolicFile::createSymbolicFile(Buf);
527
if (!ObjOrErr)
528
return ObjOrErr.takeError();
529
return std::move(*ObjOrErr);
530
}
531
}
532
533
static bool is64BitSymbolicFile(const SymbolicFile *SymObj) {
534
return SymObj != nullptr ? SymObj->is64Bit() : false;
535
}
536
537
// Log2 of PAGESIZE(4096) on an AIX system.
538
static const uint32_t Log2OfAIXPageSize = 12;
539
540
// In the AIX big archive format, since the data content follows the member file
541
// name, if the name ends on an odd byte, an extra byte will be added for
542
// padding. This ensures that the data within the member file starts at an even
543
// byte.
544
static const uint32_t MinBigArchiveMemDataAlign = 2;
545
546
template <typename AuxiliaryHeader>
547
uint16_t getAuxMaxAlignment(uint16_t AuxHeaderSize, AuxiliaryHeader *AuxHeader,
548
uint16_t Log2OfMaxAlign) {
549
// If the member doesn't have an auxiliary header, it isn't a loadable object
550
// and so it just needs aligning at the minimum value.
551
if (AuxHeader == nullptr)
552
return MinBigArchiveMemDataAlign;
553
554
// If the auxiliary header does not have both MaxAlignOfData and
555
// MaxAlignOfText field, it is not a loadable shared object file, so align at
556
// the minimum value. The 'ModuleType' member is located right after
557
// 'MaxAlignOfData' in the AuxiliaryHeader.
558
if (AuxHeaderSize < offsetof(AuxiliaryHeader, ModuleType))
559
return MinBigArchiveMemDataAlign;
560
561
// If the XCOFF object file does not have a loader section, it is not
562
// loadable, so align at the minimum value.
563
if (AuxHeader->SecNumOfLoader == 0)
564
return MinBigArchiveMemDataAlign;
565
566
// The content of the loadable member file needs to be aligned at MAX(maximum
567
// alignment of .text, maximum alignment of .data) if there are both fields.
568
// If the desired alignment is > PAGESIZE, 32-bit members are aligned on a
569
// word boundary, while 64-bit members are aligned on a PAGESIZE(2^12=4096)
570
// boundary.
571
uint16_t Log2OfAlign =
572
std::max(AuxHeader->MaxAlignOfText, AuxHeader->MaxAlignOfData);
573
return 1 << (Log2OfAlign > Log2OfAIXPageSize ? Log2OfMaxAlign : Log2OfAlign);
574
}
575
576
// AIX big archives may contain shared object members. The AIX OS requires these
577
// members to be aligned if they are 64-bit and recommends it for 32-bit
578
// members. This ensures that when these members are loaded they are aligned in
579
// memory.
580
static uint32_t getMemberAlignment(SymbolicFile *SymObj) {
581
XCOFFObjectFile *XCOFFObj = dyn_cast_or_null<XCOFFObjectFile>(SymObj);
582
if (!XCOFFObj)
583
return MinBigArchiveMemDataAlign;
584
585
// If the desired alignment is > PAGESIZE, 32-bit members are aligned on a
586
// word boundary, while 64-bit members are aligned on a PAGESIZE boundary.
587
return XCOFFObj->is64Bit()
588
? getAuxMaxAlignment(XCOFFObj->fileHeader64()->AuxHeaderSize,
589
XCOFFObj->auxiliaryHeader64(),
590
Log2OfAIXPageSize)
591
: getAuxMaxAlignment(XCOFFObj->fileHeader32()->AuxHeaderSize,
592
XCOFFObj->auxiliaryHeader32(), 2);
593
}
594
595
static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind,
596
bool Deterministic, ArrayRef<MemberData> Members,
597
StringRef StringTable, uint64_t MembersOffset,
598
unsigned NumSyms, uint64_t PrevMemberOffset = 0,
599
uint64_t NextMemberOffset = 0,
600
bool Is64Bit = false) {
601
// We don't write a symbol table on an archive with no members -- except on
602
// Darwin, where the linker will abort unless the archive has a symbol table.
603
if (StringTable.empty() && !isDarwin(Kind) && !isCOFFArchive(Kind))
604
return;
605
606
uint64_t OffsetSize = is64BitKind(Kind) ? 8 : 4;
607
uint32_t Pad;
608
uint64_t Size = computeSymbolTableSize(Kind, NumSyms, OffsetSize,
609
StringTable.size(), &Pad);
610
writeSymbolTableHeader(Out, Kind, Deterministic, Size, PrevMemberOffset,
611
NextMemberOffset);
612
613
if (isBSDLike(Kind))
614
printNBits(Out, Kind, NumSyms * 2 * OffsetSize);
615
else
616
printNBits(Out, Kind, NumSyms);
617
618
uint64_t Pos = MembersOffset;
619
for (const MemberData &M : Members) {
620
if (isAIXBigArchive(Kind)) {
621
Pos += M.PreHeadPadSize;
622
if (is64BitSymbolicFile(M.SymFile.get()) != Is64Bit) {
623
Pos += M.Header.size() + M.Data.size() + M.Padding.size();
624
continue;
625
}
626
}
627
628
for (unsigned StringOffset : M.Symbols) {
629
if (isBSDLike(Kind))
630
printNBits(Out, Kind, StringOffset);
631
printNBits(Out, Kind, Pos); // member offset
632
}
633
Pos += M.Header.size() + M.Data.size() + M.Padding.size();
634
}
635
636
if (isBSDLike(Kind))
637
// byte count of the string table
638
printNBits(Out, Kind, StringTable.size());
639
Out << StringTable;
640
641
while (Pad--)
642
Out.write(uint8_t(0));
643
}
644
645
static void writeSymbolMap(raw_ostream &Out, object::Archive::Kind Kind,
646
bool Deterministic, ArrayRef<MemberData> Members,
647
SymMap &SymMap, uint64_t MembersOffset) {
648
uint32_t Pad;
649
uint64_t Size = computeSymbolMapSize(Members.size(), SymMap, &Pad);
650
writeSymbolTableHeader(Out, Kind, Deterministic, Size, 0);
651
652
uint32_t Pos = MembersOffset;
653
654
printLE<uint32_t>(Out, Members.size());
655
for (const MemberData &M : Members) {
656
printLE(Out, Pos); // member offset
657
Pos += M.Header.size() + M.Data.size() + M.Padding.size();
658
}
659
660
printLE<uint32_t>(Out, SymMap.Map.size());
661
662
for (auto S : SymMap.Map)
663
printLE(Out, S.second);
664
for (auto S : SymMap.Map)
665
Out << S.first << '\0';
666
667
while (Pad--)
668
Out.write(uint8_t(0));
669
}
670
671
static void writeECSymbols(raw_ostream &Out, object::Archive::Kind Kind,
672
bool Deterministic, ArrayRef<MemberData> Members,
673
SymMap &SymMap) {
674
uint32_t Pad;
675
uint64_t Size = computeECSymbolsSize(SymMap, &Pad);
676
printGNUSmallMemberHeader(Out, "/<ECSYMBOLS>", now(Deterministic), 0, 0, 0,
677
Size);
678
679
printLE<uint32_t>(Out, SymMap.ECMap.size());
680
681
for (auto S : SymMap.ECMap)
682
printLE(Out, S.second);
683
for (auto S : SymMap.ECMap)
684
Out << S.first << '\0';
685
while (Pad--)
686
Out.write(uint8_t(0));
687
}
688
689
static bool isECObject(object::SymbolicFile &Obj) {
690
if (Obj.isCOFF())
691
return cast<llvm::object::COFFObjectFile>(&Obj)->getMachine() !=
692
COFF::IMAGE_FILE_MACHINE_ARM64;
693
694
if (Obj.isCOFFImportFile())
695
return cast<llvm::object::COFFImportFile>(&Obj)->getMachine() !=
696
COFF::IMAGE_FILE_MACHINE_ARM64;
697
698
if (Obj.isIR()) {
699
Expected<std::string> TripleStr =
700
getBitcodeTargetTriple(Obj.getMemoryBufferRef());
701
if (!TripleStr)
702
return false;
703
Triple T(*TripleStr);
704
return T.isWindowsArm64EC() || T.getArch() == Triple::x86_64;
705
}
706
707
return false;
708
}
709
710
static bool isAnyArm64COFF(object::SymbolicFile &Obj) {
711
if (Obj.isCOFF())
712
return COFF::isAnyArm64(cast<COFFObjectFile>(&Obj)->getMachine());
713
714
if (Obj.isCOFFImportFile())
715
return COFF::isAnyArm64(cast<COFFImportFile>(&Obj)->getMachine());
716
717
if (Obj.isIR()) {
718
Expected<std::string> TripleStr =
719
getBitcodeTargetTriple(Obj.getMemoryBufferRef());
720
if (!TripleStr)
721
return false;
722
Triple T(*TripleStr);
723
return T.isOSWindows() && T.getArch() == Triple::aarch64;
724
}
725
726
return false;
727
}
728
729
bool isImportDescriptor(StringRef Name) {
730
return Name.starts_with(ImportDescriptorPrefix) ||
731
Name == StringRef{NullImportDescriptorSymbolName} ||
732
(Name.starts_with(NullThunkDataPrefix) &&
733
Name.ends_with(NullThunkDataSuffix));
734
}
735
736
static Expected<std::vector<unsigned>> getSymbols(SymbolicFile *Obj,
737
uint16_t Index,
738
raw_ostream &SymNames,
739
SymMap *SymMap) {
740
std::vector<unsigned> Ret;
741
742
if (Obj == nullptr)
743
return Ret;
744
745
std::map<std::string, uint16_t> *Map = nullptr;
746
if (SymMap)
747
Map = SymMap->UseECMap && isECObject(*Obj) ? &SymMap->ECMap : &SymMap->Map;
748
749
for (const object::BasicSymbolRef &S : Obj->symbols()) {
750
if (!isArchiveSymbol(S))
751
continue;
752
if (Map) {
753
std::string Name;
754
raw_string_ostream NameStream(Name);
755
if (Error E = S.printName(NameStream))
756
return std::move(E);
757
if (Map->find(Name) != Map->end())
758
continue; // ignore duplicated symbol
759
(*Map)[Name] = Index;
760
if (Map == &SymMap->Map) {
761
Ret.push_back(SymNames.tell());
762
SymNames << Name << '\0';
763
// If EC is enabled, then the import descriptors are NOT put into EC
764
// objects so we need to copy them to the EC map manually.
765
if (SymMap->UseECMap && isImportDescriptor(Name))
766
SymMap->ECMap[Name] = Index;
767
}
768
} else {
769
Ret.push_back(SymNames.tell());
770
if (Error E = S.printName(SymNames))
771
return std::move(E);
772
SymNames << '\0';
773
}
774
}
775
return Ret;
776
}
777
778
static Expected<std::vector<MemberData>>
779
computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
780
object::Archive::Kind Kind, bool Thin, bool Deterministic,
781
SymtabWritingMode NeedSymbols, SymMap *SymMap,
782
LLVMContext &Context, ArrayRef<NewArchiveMember> NewMembers,
783
std::optional<bool> IsEC, function_ref<void(Error)> Warn) {
784
static char PaddingData[8] = {'\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n'};
785
uint64_t MemHeadPadSize = 0;
786
uint64_t Pos =
787
isAIXBigArchive(Kind) ? sizeof(object::BigArchive::FixLenHdr) : 0;
788
789
std::vector<MemberData> Ret;
790
bool HasObject = false;
791
792
// Deduplicate long member names in the string table and reuse earlier name
793
// offsets. This especially saves space for COFF Import libraries where all
794
// members have the same name.
795
StringMap<uint64_t> MemberNames;
796
797
// UniqueTimestamps is a special case to improve debugging on Darwin:
798
//
799
// The Darwin linker does not link debug info into the final
800
// binary. Instead, it emits entries of type N_OSO in the output
801
// binary's symbol table, containing references to the linked-in
802
// object files. Using that reference, the debugger can read the
803
// debug data directly from the object files. Alternatively, an
804
// invocation of 'dsymutil' will link the debug data from the object
805
// files into a dSYM bundle, which can be loaded by the debugger,
806
// instead of the object files.
807
//
808
// For an object file, the N_OSO entries contain the absolute path
809
// path to the file, and the file's timestamp. For an object
810
// included in an archive, the path is formatted like
811
// "/absolute/path/to/archive.a(member.o)", and the timestamp is the
812
// archive member's timestamp, rather than the archive's timestamp.
813
//
814
// However, this doesn't always uniquely identify an object within
815
// an archive -- an archive file can have multiple entries with the
816
// same filename. (This will happen commonly if the original object
817
// files started in different directories.) The only way they get
818
// distinguished, then, is via the timestamp. But this process is
819
// unable to find the correct object file in the archive when there
820
// are two files of the same name and timestamp.
821
//
822
// Additionally, timestamp==0 is treated specially, and causes the
823
// timestamp to be ignored as a match criteria.
824
//
825
// That will "usually" work out okay when creating an archive not in
826
// deterministic timestamp mode, because the objects will probably
827
// have been created at different timestamps.
828
//
829
// To ameliorate this problem, in deterministic archive mode (which
830
// is the default), on Darwin we will emit a unique non-zero
831
// timestamp for each entry with a duplicated name. This is still
832
// deterministic: the only thing affecting that timestamp is the
833
// order of the files in the resultant archive.
834
//
835
// See also the functions that handle the lookup:
836
// in lldb: ObjectContainerBSDArchive::Archive::FindObject()
837
// in llvm/tools/dsymutil: BinaryHolder::GetArchiveMemberBuffers().
838
bool UniqueTimestamps = Deterministic && isDarwin(Kind);
839
std::map<StringRef, unsigned> FilenameCount;
840
if (UniqueTimestamps) {
841
for (const NewArchiveMember &M : NewMembers)
842
FilenameCount[M.MemberName]++;
843
for (auto &Entry : FilenameCount)
844
Entry.second = Entry.second > 1 ? 1 : 0;
845
}
846
847
std::vector<std::unique_ptr<SymbolicFile>> SymFiles;
848
849
if (NeedSymbols != SymtabWritingMode::NoSymtab || isAIXBigArchive(Kind)) {
850
for (const NewArchiveMember &M : NewMembers) {
851
Expected<std::unique_ptr<SymbolicFile>> SymFileOrErr = getSymbolicFile(
852
M.Buf->getMemBufferRef(), Context, Kind, [&](Error Err) {
853
Warn(createFileError(M.MemberName, std::move(Err)));
854
});
855
if (!SymFileOrErr)
856
return createFileError(M.MemberName, SymFileOrErr.takeError());
857
SymFiles.push_back(std::move(*SymFileOrErr));
858
}
859
}
860
861
if (SymMap) {
862
if (IsEC) {
863
SymMap->UseECMap = *IsEC;
864
} else {
865
// When IsEC is not specified by the caller, use it when we have both
866
// any ARM64 object (ARM64 or ARM64EC) and any EC object (ARM64EC or
867
// AMD64). This may be a single ARM64EC object, but may also be separate
868
// ARM64 and AMD64 objects.
869
bool HaveArm64 = false, HaveEC = false;
870
for (std::unique_ptr<SymbolicFile> &SymFile : SymFiles) {
871
if (!SymFile)
872
continue;
873
if (!HaveArm64)
874
HaveArm64 = isAnyArm64COFF(*SymFile);
875
if (!HaveEC)
876
HaveEC = isECObject(*SymFile);
877
if (HaveArm64 && HaveEC) {
878
SymMap->UseECMap = true;
879
break;
880
}
881
}
882
}
883
}
884
885
// The big archive format needs to know the offset of the previous member
886
// header.
887
uint64_t PrevOffset = 0;
888
uint64_t NextMemHeadPadSize = 0;
889
890
for (uint32_t Index = 0; Index < NewMembers.size(); ++Index) {
891
const NewArchiveMember *M = &NewMembers[Index];
892
std::string Header;
893
raw_string_ostream Out(Header);
894
895
MemoryBufferRef Buf = M->Buf->getMemBufferRef();
896
StringRef Data = Thin ? "" : Buf.getBuffer();
897
898
// ld64 expects the members to be 8-byte aligned for 64-bit content and at
899
// least 4-byte aligned for 32-bit content. Opt for the larger encoding
900
// uniformly. This matches the behaviour with cctools and ensures that ld64
901
// is happy with archives that we generate.
902
unsigned MemberPadding =
903
isDarwin(Kind) ? offsetToAlignment(Data.size(), Align(8)) : 0;
904
unsigned TailPadding =
905
offsetToAlignment(Data.size() + MemberPadding, Align(2));
906
StringRef Padding = StringRef(PaddingData, MemberPadding + TailPadding);
907
908
sys::TimePoint<std::chrono::seconds> ModTime;
909
if (UniqueTimestamps)
910
// Increment timestamp for each file of a given name.
911
ModTime = sys::toTimePoint(FilenameCount[M->MemberName]++);
912
else
913
ModTime = M->ModTime;
914
915
uint64_t Size = Buf.getBufferSize() + MemberPadding;
916
if (Size > object::Archive::MaxMemberSize) {
917
std::string StringMsg =
918
"File " + M->MemberName.str() + " exceeds size limit";
919
return make_error<object::GenericBinaryError>(
920
std::move(StringMsg), object::object_error::parse_failed);
921
}
922
923
std::unique_ptr<SymbolicFile> CurSymFile;
924
if (!SymFiles.empty())
925
CurSymFile = std::move(SymFiles[Index]);
926
927
// In the big archive file format, we need to calculate and include the next
928
// member offset and previous member offset in the file member header.
929
if (isAIXBigArchive(Kind)) {
930
uint64_t OffsetToMemData = Pos + sizeof(object::BigArMemHdrType) +
931
alignTo(M->MemberName.size(), 2);
932
933
if (M == NewMembers.begin())
934
NextMemHeadPadSize =
935
alignToPowerOf2(OffsetToMemData,
936
getMemberAlignment(CurSymFile.get())) -
937
OffsetToMemData;
938
939
MemHeadPadSize = NextMemHeadPadSize;
940
Pos += MemHeadPadSize;
941
uint64_t NextOffset = Pos + sizeof(object::BigArMemHdrType) +
942
alignTo(M->MemberName.size(), 2) + alignTo(Size, 2);
943
944
// If there is another member file after this, we need to calculate the
945
// padding before the header.
946
if (Index + 1 != SymFiles.size()) {
947
uint64_t OffsetToNextMemData =
948
NextOffset + sizeof(object::BigArMemHdrType) +
949
alignTo(NewMembers[Index + 1].MemberName.size(), 2);
950
NextMemHeadPadSize =
951
alignToPowerOf2(OffsetToNextMemData,
952
getMemberAlignment(SymFiles[Index + 1].get())) -
953
OffsetToNextMemData;
954
NextOffset += NextMemHeadPadSize;
955
}
956
printBigArchiveMemberHeader(Out, M->MemberName, ModTime, M->UID, M->GID,
957
M->Perms, Size, PrevOffset, NextOffset);
958
PrevOffset = Pos;
959
} else {
960
printMemberHeader(Out, Pos, StringTable, MemberNames, Kind, Thin, *M,
961
ModTime, Size);
962
}
963
Out.flush();
964
965
std::vector<unsigned> Symbols;
966
if (NeedSymbols != SymtabWritingMode::NoSymtab) {
967
Expected<std::vector<unsigned>> SymbolsOrErr =
968
getSymbols(CurSymFile.get(), Index + 1, SymNames, SymMap);
969
if (!SymbolsOrErr)
970
return createFileError(M->MemberName, SymbolsOrErr.takeError());
971
Symbols = std::move(*SymbolsOrErr);
972
if (CurSymFile)
973
HasObject = true;
974
}
975
976
Pos += Header.size() + Data.size() + Padding.size();
977
Ret.push_back({std::move(Symbols), std::move(Header), Data, Padding,
978
MemHeadPadSize, std::move(CurSymFile)});
979
}
980
// If there are no symbols, emit an empty symbol table, to satisfy Solaris
981
// tools, older versions of which expect a symbol table in a non-empty
982
// archive, regardless of whether there are any symbols in it.
983
if (HasObject && SymNames.tell() == 0 && !isCOFFArchive(Kind))
984
SymNames << '\0' << '\0' << '\0';
985
return std::move(Ret);
986
}
987
988
namespace llvm {
989
990
static ErrorOr<SmallString<128>> canonicalizePath(StringRef P) {
991
SmallString<128> Ret = P;
992
std::error_code Err = sys::fs::make_absolute(Ret);
993
if (Err)
994
return Err;
995
sys::path::remove_dots(Ret, /*removedotdot*/ true);
996
return Ret;
997
}
998
999
// Compute the relative path from From to To.
1000
Expected<std::string> computeArchiveRelativePath(StringRef From, StringRef To) {
1001
ErrorOr<SmallString<128>> PathToOrErr = canonicalizePath(To);
1002
ErrorOr<SmallString<128>> DirFromOrErr = canonicalizePath(From);
1003
if (!PathToOrErr || !DirFromOrErr)
1004
return errorCodeToError(errnoAsErrorCode());
1005
1006
const SmallString<128> &PathTo = *PathToOrErr;
1007
const SmallString<128> &DirFrom = sys::path::parent_path(*DirFromOrErr);
1008
1009
// Can't construct a relative path between different roots
1010
if (sys::path::root_name(PathTo) != sys::path::root_name(DirFrom))
1011
return sys::path::convert_to_slash(PathTo);
1012
1013
// Skip common prefixes
1014
auto FromTo =
1015
std::mismatch(sys::path::begin(DirFrom), sys::path::end(DirFrom),
1016
sys::path::begin(PathTo));
1017
auto FromI = FromTo.first;
1018
auto ToI = FromTo.second;
1019
1020
// Construct relative path
1021
SmallString<128> Relative;
1022
for (auto FromE = sys::path::end(DirFrom); FromI != FromE; ++FromI)
1023
sys::path::append(Relative, sys::path::Style::posix, "..");
1024
1025
for (auto ToE = sys::path::end(PathTo); ToI != ToE; ++ToI)
1026
sys::path::append(Relative, sys::path::Style::posix, *ToI);
1027
1028
return std::string(Relative);
1029
}
1030
1031
Error writeArchiveToStream(raw_ostream &Out,
1032
ArrayRef<NewArchiveMember> NewMembers,
1033
SymtabWritingMode WriteSymtab,
1034
object::Archive::Kind Kind, bool Deterministic,
1035
bool Thin, std::optional<bool> IsEC,
1036
function_ref<void(Error)> Warn) {
1037
assert((!Thin || !isBSDLike(Kind)) && "Only the gnu format has a thin mode");
1038
1039
SmallString<0> SymNamesBuf;
1040
raw_svector_ostream SymNames(SymNamesBuf);
1041
SmallString<0> StringTableBuf;
1042
raw_svector_ostream StringTable(StringTableBuf);
1043
SymMap SymMap;
1044
bool ShouldWriteSymtab = WriteSymtab != SymtabWritingMode::NoSymtab;
1045
1046
// COFF symbol map uses 16-bit indexes, so we can't use it if there are too
1047
// many members. COFF format also requires symbol table presence, so use
1048
// GNU format when NoSymtab is requested.
1049
if (isCOFFArchive(Kind) && (NewMembers.size() > 0xfffe || !ShouldWriteSymtab))
1050
Kind = object::Archive::K_GNU;
1051
1052
// In the scenario when LLVMContext is populated SymbolicFile will contain a
1053
// reference to it, thus SymbolicFile should be destroyed first.
1054
LLVMContext Context;
1055
1056
Expected<std::vector<MemberData>> DataOrErr = computeMemberData(
1057
StringTable, SymNames, Kind, Thin, Deterministic, WriteSymtab,
1058
isCOFFArchive(Kind) ? &SymMap : nullptr, Context, NewMembers, IsEC, Warn);
1059
if (Error E = DataOrErr.takeError())
1060
return E;
1061
std::vector<MemberData> &Data = *DataOrErr;
1062
1063
uint64_t StringTableSize = 0;
1064
MemberData StringTableMember;
1065
if (!StringTableBuf.empty() && !isAIXBigArchive(Kind)) {
1066
StringTableMember = computeStringTable(StringTableBuf);
1067
StringTableSize = StringTableMember.Header.size() +
1068
StringTableMember.Data.size() +
1069
StringTableMember.Padding.size();
1070
}
1071
1072
// We would like to detect if we need to switch to a 64-bit symbol table.
1073
uint64_t LastMemberEndOffset = 0;
1074
uint64_t LastMemberHeaderOffset = 0;
1075
uint64_t NumSyms = 0;
1076
uint64_t NumSyms32 = 0; // Store symbol number of 32-bit member files.
1077
1078
for (const auto &M : Data) {
1079
// Record the start of the member's offset
1080
LastMemberEndOffset += M.PreHeadPadSize;
1081
LastMemberHeaderOffset = LastMemberEndOffset;
1082
// Account for the size of each part associated with the member.
1083
LastMemberEndOffset += M.Header.size() + M.Data.size() + M.Padding.size();
1084
NumSyms += M.Symbols.size();
1085
1086
// AIX big archive files may contain two global symbol tables. The
1087
// first global symbol table locates 32-bit file members that define global
1088
// symbols; the second global symbol table does the same for 64-bit file
1089
// members. As a big archive can have both 32-bit and 64-bit file members,
1090
// we need to know the number of symbols in each symbol table individually.
1091
if (isAIXBigArchive(Kind) && ShouldWriteSymtab) {
1092
if (!is64BitSymbolicFile(M.SymFile.get()))
1093
NumSyms32 += M.Symbols.size();
1094
}
1095
}
1096
1097
std::optional<uint64_t> HeadersSize;
1098
1099
// The symbol table is put at the end of the big archive file. The symbol
1100
// table is at the start of the archive file for other archive formats.
1101
if (ShouldWriteSymtab && !is64BitKind(Kind)) {
1102
// We assume 32-bit offsets to see if 32-bit symbols are possible or not.
1103
HeadersSize = computeHeadersSize(Kind, Data.size(), StringTableSize,
1104
NumSyms, SymNamesBuf.size(),
1105
isCOFFArchive(Kind) ? &SymMap : nullptr);
1106
1107
// The SYM64 format is used when an archive's member offsets are larger than
1108
// 32-bits can hold. The need for this shift in format is detected by
1109
// writeArchive. To test this we need to generate a file with a member that
1110
// has an offset larger than 32-bits but this demands a very slow test. To
1111
// speed the test up we use this environment variable to pretend like the
1112
// cutoff happens before 32-bits and instead happens at some much smaller
1113
// value.
1114
uint64_t Sym64Threshold = 1ULL << 32;
1115
const char *Sym64Env = std::getenv("SYM64_THRESHOLD");
1116
if (Sym64Env)
1117
StringRef(Sym64Env).getAsInteger(10, Sym64Threshold);
1118
1119
// If LastMemberHeaderOffset isn't going to fit in a 32-bit varible we need
1120
// to switch to 64-bit. Note that the file can be larger than 4GB as long as
1121
// the last member starts before the 4GB offset.
1122
if (*HeadersSize + LastMemberHeaderOffset >= Sym64Threshold) {
1123
if (Kind == object::Archive::K_DARWIN)
1124
Kind = object::Archive::K_DARWIN64;
1125
else
1126
Kind = object::Archive::K_GNU64;
1127
HeadersSize.reset();
1128
}
1129
}
1130
1131
if (Thin)
1132
Out << "!<thin>\n";
1133
else if (isAIXBigArchive(Kind))
1134
Out << "<bigaf>\n";
1135
else
1136
Out << "!<arch>\n";
1137
1138
if (!isAIXBigArchive(Kind)) {
1139
if (ShouldWriteSymtab) {
1140
if (!HeadersSize)
1141
HeadersSize = computeHeadersSize(
1142
Kind, Data.size(), StringTableSize, NumSyms, SymNamesBuf.size(),
1143
isCOFFArchive(Kind) ? &SymMap : nullptr);
1144
writeSymbolTable(Out, Kind, Deterministic, Data, SymNamesBuf,
1145
*HeadersSize, NumSyms);
1146
1147
if (isCOFFArchive(Kind))
1148
writeSymbolMap(Out, Kind, Deterministic, Data, SymMap, *HeadersSize);
1149
}
1150
1151
if (StringTableSize)
1152
Out << StringTableMember.Header << StringTableMember.Data
1153
<< StringTableMember.Padding;
1154
1155
if (ShouldWriteSymtab && SymMap.ECMap.size())
1156
writeECSymbols(Out, Kind, Deterministic, Data, SymMap);
1157
1158
for (const MemberData &M : Data)
1159
Out << M.Header << M.Data << M.Padding;
1160
} else {
1161
HeadersSize = sizeof(object::BigArchive::FixLenHdr);
1162
LastMemberEndOffset += *HeadersSize;
1163
LastMemberHeaderOffset += *HeadersSize;
1164
1165
// For the big archive (AIX) format, compute a table of member names and
1166
// offsets, used in the member table.
1167
uint64_t MemberTableNameStrTblSize = 0;
1168
std::vector<size_t> MemberOffsets;
1169
std::vector<StringRef> MemberNames;
1170
// Loop across object to find offset and names.
1171
uint64_t MemberEndOffset = sizeof(object::BigArchive::FixLenHdr);
1172
for (size_t I = 0, Size = NewMembers.size(); I != Size; ++I) {
1173
const NewArchiveMember &Member = NewMembers[I];
1174
MemberTableNameStrTblSize += Member.MemberName.size() + 1;
1175
MemberEndOffset += Data[I].PreHeadPadSize;
1176
MemberOffsets.push_back(MemberEndOffset);
1177
MemberNames.push_back(Member.MemberName);
1178
// File member name ended with "`\n". The length is included in
1179
// BigArMemHdrType.
1180
MemberEndOffset += sizeof(object::BigArMemHdrType) +
1181
alignTo(Data[I].Data.size(), 2) +
1182
alignTo(Member.MemberName.size(), 2);
1183
}
1184
1185
// AIX member table size.
1186
uint64_t MemberTableSize = 20 + // Number of members field
1187
20 * MemberOffsets.size() +
1188
MemberTableNameStrTblSize;
1189
1190
SmallString<0> SymNamesBuf32;
1191
SmallString<0> SymNamesBuf64;
1192
raw_svector_ostream SymNames32(SymNamesBuf32);
1193
raw_svector_ostream SymNames64(SymNamesBuf64);
1194
1195
if (ShouldWriteSymtab && NumSyms)
1196
// Generate the symbol names for the members.
1197
for (const auto &M : Data) {
1198
Expected<std::vector<unsigned>> SymbolsOrErr = getSymbols(
1199
M.SymFile.get(), 0,
1200
is64BitSymbolicFile(M.SymFile.get()) ? SymNames64 : SymNames32,
1201
nullptr);
1202
if (!SymbolsOrErr)
1203
return SymbolsOrErr.takeError();
1204
}
1205
1206
uint64_t MemberTableEndOffset =
1207
LastMemberEndOffset +
1208
alignTo(sizeof(object::BigArMemHdrType) + MemberTableSize, 2);
1209
1210
// In AIX OS, The 'GlobSymOffset' field in the fixed-length header contains
1211
// the offset to the 32-bit global symbol table, and the 'GlobSym64Offset'
1212
// contains the offset to the 64-bit global symbol table.
1213
uint64_t GlobalSymbolOffset =
1214
(ShouldWriteSymtab &&
1215
(WriteSymtab != SymtabWritingMode::BigArchive64) && NumSyms32 > 0)
1216
? MemberTableEndOffset
1217
: 0;
1218
1219
uint64_t GlobalSymbolOffset64 = 0;
1220
uint64_t NumSyms64 = NumSyms - NumSyms32;
1221
if (ShouldWriteSymtab && (WriteSymtab != SymtabWritingMode::BigArchive32) &&
1222
NumSyms64 > 0) {
1223
if (GlobalSymbolOffset == 0)
1224
GlobalSymbolOffset64 = MemberTableEndOffset;
1225
else
1226
// If there is a global symbol table for 32-bit members,
1227
// the 64-bit global symbol table is after the 32-bit one.
1228
GlobalSymbolOffset64 =
1229
GlobalSymbolOffset + sizeof(object::BigArMemHdrType) +
1230
(NumSyms32 + 1) * 8 + alignTo(SymNamesBuf32.size(), 2);
1231
}
1232
1233
// Fixed Sized Header.
1234
printWithSpacePadding(Out, NewMembers.size() ? LastMemberEndOffset : 0,
1235
20); // Offset to member table
1236
// If there are no file members in the archive, there will be no global
1237
// symbol table.
1238
printWithSpacePadding(Out, GlobalSymbolOffset, 20);
1239
printWithSpacePadding(Out, GlobalSymbolOffset64, 20);
1240
printWithSpacePadding(Out,
1241
NewMembers.size()
1242
? sizeof(object::BigArchive::FixLenHdr) +
1243
Data[0].PreHeadPadSize
1244
: 0,
1245
20); // Offset to first archive member
1246
printWithSpacePadding(Out, NewMembers.size() ? LastMemberHeaderOffset : 0,
1247
20); // Offset to last archive member
1248
printWithSpacePadding(
1249
Out, 0,
1250
20); // Offset to first member of free list - Not supported yet
1251
1252
for (const MemberData &M : Data) {
1253
Out << std::string(M.PreHeadPadSize, '\0');
1254
Out << M.Header << M.Data;
1255
if (M.Data.size() % 2)
1256
Out << '\0';
1257
}
1258
1259
if (NewMembers.size()) {
1260
// Member table.
1261
printBigArchiveMemberHeader(Out, "", sys::toTimePoint(0), 0, 0, 0,
1262
MemberTableSize, LastMemberHeaderOffset,
1263
GlobalSymbolOffset ? GlobalSymbolOffset
1264
: GlobalSymbolOffset64);
1265
printWithSpacePadding(Out, MemberOffsets.size(), 20); // Number of members
1266
for (uint64_t MemberOffset : MemberOffsets)
1267
printWithSpacePadding(Out, MemberOffset,
1268
20); // Offset to member file header.
1269
for (StringRef MemberName : MemberNames)
1270
Out << MemberName << '\0'; // Member file name, null byte padding.
1271
1272
if (MemberTableNameStrTblSize % 2)
1273
Out << '\0'; // Name table must be tail padded to an even number of
1274
// bytes.
1275
1276
if (ShouldWriteSymtab) {
1277
// Write global symbol table for 32-bit file members.
1278
if (GlobalSymbolOffset) {
1279
writeSymbolTable(Out, Kind, Deterministic, Data, SymNamesBuf32,
1280
*HeadersSize, NumSyms32, LastMemberEndOffset,
1281
GlobalSymbolOffset64);
1282
// Add padding between the symbol tables, if needed.
1283
if (GlobalSymbolOffset64 && (SymNamesBuf32.size() % 2))
1284
Out << '\0';
1285
}
1286
1287
// Write global symbol table for 64-bit file members.
1288
if (GlobalSymbolOffset64)
1289
writeSymbolTable(Out, Kind, Deterministic, Data, SymNamesBuf64,
1290
*HeadersSize, NumSyms64,
1291
GlobalSymbolOffset ? GlobalSymbolOffset
1292
: LastMemberEndOffset,
1293
0, true);
1294
}
1295
}
1296
}
1297
Out.flush();
1298
return Error::success();
1299
}
1300
1301
void warnToStderr(Error Err) {
1302
llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), "warning: ");
1303
}
1304
1305
Error writeArchive(StringRef ArcName, ArrayRef<NewArchiveMember> NewMembers,
1306
SymtabWritingMode WriteSymtab, object::Archive::Kind Kind,
1307
bool Deterministic, bool Thin,
1308
std::unique_ptr<MemoryBuffer> OldArchiveBuf,
1309
std::optional<bool> IsEC, function_ref<void(Error)> Warn) {
1310
Expected<sys::fs::TempFile> Temp =
1311
sys::fs::TempFile::create(ArcName + ".temp-archive-%%%%%%%.a");
1312
if (!Temp)
1313
return Temp.takeError();
1314
raw_fd_ostream Out(Temp->FD, false);
1315
1316
if (Error E = writeArchiveToStream(Out, NewMembers, WriteSymtab, Kind,
1317
Deterministic, Thin, IsEC, Warn)) {
1318
if (Error DiscardError = Temp->discard())
1319
return joinErrors(std::move(E), std::move(DiscardError));
1320
return E;
1321
}
1322
1323
// At this point, we no longer need whatever backing memory
1324
// was used to generate the NewMembers. On Windows, this buffer
1325
// could be a mapped view of the file we want to replace (if
1326
// we're updating an existing archive, say). In that case, the
1327
// rename would still succeed, but it would leave behind a
1328
// temporary file (actually the original file renamed) because
1329
// a file cannot be deleted while there's a handle open on it,
1330
// only renamed. So by freeing this buffer, this ensures that
1331
// the last open handle on the destination file, if any, is
1332
// closed before we attempt to rename.
1333
OldArchiveBuf.reset();
1334
1335
return Temp->keep(ArcName);
1336
}
1337
1338
Expected<std::unique_ptr<MemoryBuffer>>
1339
writeArchiveToBuffer(ArrayRef<NewArchiveMember> NewMembers,
1340
SymtabWritingMode WriteSymtab, object::Archive::Kind Kind,
1341
bool Deterministic, bool Thin,
1342
function_ref<void(Error)> Warn) {
1343
SmallVector<char, 0> ArchiveBufferVector;
1344
raw_svector_ostream ArchiveStream(ArchiveBufferVector);
1345
1346
if (Error E =
1347
writeArchiveToStream(ArchiveStream, NewMembers, WriteSymtab, Kind,
1348
Deterministic, Thin, std::nullopt, Warn))
1349
return std::move(E);
1350
1351
return std::make_unique<SmallVectorMemoryBuffer>(
1352
std::move(ArchiveBufferVector), /*RequiresNullTerminator=*/false);
1353
}
1354
1355
} // namespace llvm
1356
1357