25
25
#include " llvm/Support/Errc.h"
26
26
#include " llvm/Support/ErrorHandling.h"
27
27
#include " llvm/Support/Format.h"
28
+ #include " llvm/Support/MathExtras.h"
28
29
#include " llvm/Support/Path.h"
29
30
#include " llvm/Support/SmallVectorMemoryBuffer.h"
30
31
#include " llvm/Support/raw_ostream.h"
@@ -127,16 +128,20 @@ static bool isDarwin(object::Archive::Kind Kind) {
127
128
Kind == object::Archive::K_DARWIN64;
128
129
}
129
130
131
+ static bool isAIXBigArchive (object::Archive::Kind Kind) {
132
+ return Kind == object::Archive::K_AIXBIG;
133
+ }
134
+
130
135
static bool isBSDLike (object::Archive::Kind Kind) {
131
136
switch (Kind) {
132
137
case object::Archive::K_GNU:
133
138
case object::Archive::K_GNU64:
139
+ case object::Archive::K_AIXBIG:
134
140
return false ;
135
141
case object::Archive::K_BSD:
136
142
case object::Archive::K_DARWIN:
137
143
case object::Archive::K_DARWIN64:
138
144
return true ;
139
- case object::Archive::K_AIXBIG:
140
145
case object::Archive::K_COFF:
141
146
break ;
142
147
}
@@ -189,6 +194,31 @@ printBSDMemberHeader(raw_ostream &Out, uint64_t Pos, StringRef Name,
189
194
Out.write (uint8_t (0 ));
190
195
}
191
196
197
+ static void
198
+ printBigArchiveMemberHeader (raw_ostream &Out, StringRef Name,
199
+ const sys::TimePoint<std::chrono::seconds> &ModTime,
200
+ unsigned UID, unsigned GID, unsigned Perms,
201
+ uint64_t Size, unsigned PrevOffset,
202
+ unsigned NextOffset) {
203
+ unsigned NameLen = Name.size ();
204
+
205
+ printWithSpacePadding (Out, Size, 20 ); // File member size
206
+ printWithSpacePadding (Out, NextOffset, 20 ); // Next member header offset
207
+ printWithSpacePadding (Out, PrevOffset, 20 ); // Previous member header offset
208
+ printWithSpacePadding (Out, sys::toTimeT (ModTime), 12 ); // File member date
209
+ // The big archive format has 12 chars for uid and gid.
210
+ printWithSpacePadding (Out, UID % 1000000000000 , 12 ); // UID
211
+ printWithSpacePadding (Out, GID % 1000000000000 , 12 ); // GID
212
+ printWithSpacePadding (Out, format (" %o" , Perms), 12 ); // Permission
213
+ printWithSpacePadding (Out, NameLen, 4 ); // Name length
214
+ if (NameLen) {
215
+ printWithSpacePadding (Out, Name, NameLen); // Name
216
+ if (NameLen % 2 )
217
+ Out.write (uint8_t (0 )); // Null byte padding
218
+ }
219
+ Out << " `\n " ; // Terminator
220
+ }
221
+
192
222
static bool useStringTable (bool Thin, StringRef Name) {
193
223
return Thin || Name.size () >= 16 || Name.contains (' /' );
194
224
}
@@ -199,8 +229,8 @@ static bool is64BitKind(object::Archive::Kind Kind) {
199
229
case object::Archive::K_BSD:
200
230
case object::Archive::K_DARWIN:
201
231
case object::Archive::K_COFF:
202
- case object::Archive::K_AIXBIG:
203
232
return false ;
233
+ case object::Archive::K_AIXBIG:
204
234
case object::Archive::K_DARWIN64:
205
235
case object::Archive::K_GNU64:
206
236
return true ;
@@ -304,19 +334,27 @@ static uint64_t computeSymbolTableSize(object::Archive::Kind Kind,
304
334
// least 4-byte aligned for 32-bit content. Opt for the larger encoding
305
335
// uniformly.
306
336
// We do this for all bsd formats because it simplifies aligning members.
307
- uint32_t Pad = offsetToAlignment (Size, Align (isBSDLike (Kind) ? 8 : 2 ));
337
+ // For the big archive format, the symbol table is the last member, so there
338
+ // is no need to align.
339
+ uint32_t Pad = isAIXBigArchive (Kind)
340
+ ? 0
341
+ : offsetToAlignment (Size, Align (isBSDLike (Kind) ? 8 : 2 ));
308
342
Size += Pad;
309
343
if (Padding)
310
344
*Padding = Pad;
311
345
return Size;
312
346
}
313
347
314
348
static void writeSymbolTableHeader (raw_ostream &Out, object::Archive::Kind Kind,
315
- bool Deterministic, uint64_t Size) {
349
+ bool Deterministic, uint64_t Size,
350
+ uint64_t PrevMemberOffset = 0 ) {
316
351
if (isBSDLike (Kind)) {
317
352
const char *Name = is64BitKind (Kind) ? " __.SYMDEF_64" : " __.SYMDEF" ;
318
353
printBSDMemberHeader (Out, Out.tell (), Name, now (Deterministic), 0 , 0 , 0 ,
319
354
Size);
355
+ } else if (isAIXBigArchive (Kind)) {
356
+ printBigArchiveMemberHeader (Out, " " , now (Deterministic), 0 , 0 ,
357
+ 0 , Size, PrevMemberOffset, 0 );
320
358
} else {
321
359
const char *Name = is64BitKind (Kind) ? " /SYM64" : " " ;
322
360
printGNUSmallMemberHeader (Out, Name, now (Deterministic), 0 , 0 , 0 , Size);
@@ -325,7 +363,8 @@ static void writeSymbolTableHeader(raw_ostream &Out, object::Archive::Kind Kind,
325
363
326
364
static void writeSymbolTable (raw_ostream &Out, object::Archive::Kind Kind,
327
365
bool Deterministic, ArrayRef<MemberData> Members,
328
- StringRef StringTable) {
366
+ StringRef StringTable,
367
+ uint64_t PrevMemberOffset = 0 ) {
329
368
// We don't write a symbol table on an archive with no members -- except on
330
369
// Darwin, where the linker will abort unless the archive has a symbol table.
331
370
if (StringTable.empty () && !isDarwin (Kind))
@@ -338,9 +377,10 @@ static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind,
338
377
uint64_t OffsetSize = is64BitKind (Kind) ? 8 : 4 ;
339
378
uint32_t Pad;
340
379
uint64_t Size = computeSymbolTableSize (Kind, NumSyms, OffsetSize, StringTable, &Pad);
341
- writeSymbolTableHeader (Out, Kind, Deterministic, Size);
380
+ writeSymbolTableHeader (Out, Kind, Deterministic, Size, PrevMemberOffset );
342
381
343
- uint64_t Pos = Out.tell () + Size;
382
+ uint64_t Pos = isAIXBigArchive (Kind) ? sizeof (object::BigArchive::FixLenHdr)
383
+ : Out.tell () + Size;
344
384
345
385
if (isBSDLike (Kind))
346
386
printNBits (Out, Kind, NumSyms * 2 * OffsetSize);
@@ -409,9 +449,8 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
409
449
bool NeedSymbols, ArrayRef<NewArchiveMember> NewMembers) {
410
450
static char PaddingData[8 ] = {' \n ' , ' \n ' , ' \n ' , ' \n ' , ' \n ' , ' \n ' , ' \n ' , ' \n ' };
411
451
412
- // This ignores the symbol table, but we only need the value mod 8 and the
413
- // symbol table is aligned to be a multiple of 8 bytes
414
- uint64_t Pos = 0 ;
452
+ uint64_t Pos =
453
+ isAIXBigArchive (Kind) ? sizeof (object::BigArchive::FixLenHdr) : 0 ;
415
454
416
455
std::vector<MemberData> Ret;
417
456
bool HasObject = false ;
@@ -471,6 +510,9 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
471
510
Entry.second = Entry.second > 1 ? 1 : 0 ;
472
511
}
473
512
513
+ // The big archive format needs to know the offset of the previous member
514
+ // header.
515
+ unsigned PrevOffset = 0 ;
474
516
for (const NewArchiveMember &M : NewMembers) {
475
517
std::string Header;
476
518
raw_string_ostream Out (Header);
@@ -503,8 +545,16 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
503
545
std::move (StringMsg), object::object_error::parse_failed);
504
546
}
505
547
506
- printMemberHeader (Out, Pos, StringTable, MemberNames, Kind, Thin, M,
507
- ModTime, Size);
548
+ if (isAIXBigArchive (Kind)) {
549
+ unsigned NextOffset = Pos + sizeof (object::BigArMemHdrType) +
550
+ alignTo (M.MemberName .size (), 2 ) + alignTo (Size, 2 );
551
+ printBigArchiveMemberHeader (Out, M.MemberName , ModTime, M.UID , M.GID ,
552
+ M.Perms , Size, PrevOffset, NextOffset);
553
+ PrevOffset = Pos;
554
+ } else {
555
+ printMemberHeader (Out, Pos, StringTable, MemberNames, Kind, Thin, M,
556
+ ModTime, Size);
557
+ }
508
558
Out.flush ();
509
559
510
560
std::vector<unsigned > Symbols;
@@ -588,22 +638,25 @@ static Error writeArchiveToStream(raw_ostream &Out,
588
638
return E;
589
639
std::vector<MemberData> &Data = *DataOrErr;
590
640
591
- if (!StringTableBuf.empty ())
641
+ if (!StringTableBuf.empty () && ! isAIXBigArchive (Kind) )
592
642
Data.insert (Data.begin (), computeStringTable (StringTableBuf));
593
643
594
644
// We would like to detect if we need to switch to a 64-bit symbol table.
595
- if (WriteSymtab) {
596
- uint64_t MaxOffset = 8 ; // For the file signature.
597
- uint64_t LastOffset = MaxOffset ;
598
- uint64_t NumSyms = 0 ;
599
- for (const auto &M : Data) {
600
- // Record the start of the member's offset
601
- LastOffset = MaxOffset ;
602
- // Account for the size of each part associated with the member.
603
- MaxOffset += M.Header .size () + M.Data .size () + M.Padding .size ();
604
- NumSyms += M.Symbols .size ();
605
- }
645
+ uint64_t LastMemberEndOffset =
646
+ isAIXBigArchive (Kind) ? sizeof (object::BigArchive::FixLenHdr) : 8 ;
647
+ uint64_t LastMemberHeaderOffset = LastMemberEndOffset ;
648
+ uint64_t NumSyms = 0 ;
649
+ for (const auto &M : Data) {
650
+ // Record the start of the member's offset
651
+ LastMemberHeaderOffset = LastMemberEndOffset ;
652
+ // Account for the size of each part associated with the member.
653
+ LastMemberEndOffset += M.Header .size () + M.Data .size () + M.Padding .size ();
654
+ NumSyms += M.Symbols .size ();
655
+ }
606
656
657
+ // The symbol table is put at the end of the big archive file. The symbol
658
+ // table is at the start of the archive file for other archive formats.
659
+ if (WriteSymtab && !isAIXBigArchive (Kind)) {
607
660
// We assume 32-bit offsets to see if 32-bit symbols are possible or not.
608
661
uint64_t SymtabSize = computeSymbolTableSize (Kind, NumSyms, 4 , SymNamesBuf);
609
662
auto computeSymbolTableHeaderSize =
@@ -613,7 +666,7 @@ static Error writeArchiveToStream(raw_ostream &Out,
613
666
writeSymbolTableHeader (Tmp, Kind, Deterministic, SymtabSize);
614
667
return TmpBuf.size ();
615
668
};
616
- LastOffset += computeSymbolTableHeaderSize () + SymtabSize;
669
+ LastMemberHeaderOffset += computeSymbolTableHeaderSize () + SymtabSize;
617
670
618
671
// The SYM64 format is used when an archive's member offsets are larger than
619
672
// 32-bits can hold. The need for this shift in format is detected by
@@ -627,10 +680,10 @@ static Error writeArchiveToStream(raw_ostream &Out,
627
680
if (Sym64Env)
628
681
StringRef (Sym64Env).getAsInteger (10 , Sym64Threshold);
629
682
630
- // If LastOffset isn't going to fit in a 32-bit varible we need to switch
631
- // to 64-bit. Note that the file can be larger than 4GB as long as the last
632
- // member starts before the 4GB offset.
633
- if (LastOffset >= Sym64Threshold) {
683
+ // If LastMemberHeaderOffset isn't going to fit in a 32-bit varible we need
684
+ // to switch to 64-bit. Note that the file can be larger than 4GB as long as
685
+ // the last member starts before the 4GB offset.
686
+ if (LastMemberHeaderOffset >= Sym64Threshold) {
634
687
if (Kind == object::Archive::K_DARWIN)
635
688
Kind = object::Archive::K_DARWIN64;
636
689
else
@@ -640,15 +693,92 @@ static Error writeArchiveToStream(raw_ostream &Out,
640
693
641
694
if (Thin)
642
695
Out << " !<thin>\n " ;
696
+ else if (isAIXBigArchive (Kind))
697
+ Out << " <bigaf>\n " ;
643
698
else
644
699
Out << " !<arch>\n " ;
645
700
646
- if (WriteSymtab)
647
- writeSymbolTable (Out, Kind, Deterministic, Data, SymNamesBuf);
701
+ if (!isAIXBigArchive (Kind)) {
702
+ if (WriteSymtab)
703
+ writeSymbolTable (Out, Kind, Deterministic, Data, SymNamesBuf);
704
+ for (const MemberData &M : Data)
705
+ Out << M.Header << M.Data << M.Padding ;
706
+ } else {
707
+ // For the big archive (AIX) format, compute a table of member names and
708
+ // offsets, used in the member table.
709
+ uint64_t MemberTableNameStrTblSize = 0 ;
710
+ std::vector<size_t > MemberOffsets;
711
+ std::vector<StringRef> MemberNames;
712
+ // Loop across object to find offset and names.
713
+ uint64_t MemberEndOffset = sizeof (object::BigArchive::FixLenHdr);
714
+ for (size_t I = 0 , Size = NewMembers.size (); I != Size; ++I) {
715
+ const NewArchiveMember &Member = NewMembers[I];
716
+ MemberTableNameStrTblSize += Member.MemberName .size () + 1 ;
717
+ MemberOffsets.push_back (MemberEndOffset);
718
+ MemberNames.push_back (Member.MemberName );
719
+ // File member name ended with "`\n". The length is included in
720
+ // BigArMemHdrType.
721
+ MemberEndOffset += sizeof (object::BigArMemHdrType) +
722
+ alignTo (Data[I].Data .size (), 2 ) +
723
+ alignTo (Member.MemberName .size (), 2 );
724
+ }
648
725
649
- for (const MemberData &M : Data)
650
- Out << M.Header << M.Data << M.Padding ;
726
+ // AIX member table size.
727
+ unsigned MemberTableSize = 20 + // Number of members field
728
+ 20 * MemberOffsets.size () +
729
+ MemberTableNameStrTblSize;
730
+
731
+ unsigned GlobalSymbolOffset =
732
+ (WriteSymtab && NumSyms > 0 )
733
+ ? LastMemberEndOffset +
734
+ alignTo (sizeof (object::BigArMemHdrType) + MemberTableSize, 2 )
735
+ : 0 ;
736
+
737
+ // Fixed Sized Header.
738
+ printWithSpacePadding (Out, NewMembers.size () ? LastMemberEndOffset : 0 ,
739
+ 20 ); // Offset to member table
740
+ // If there are no file members in the archive, there will be no global
741
+ // symbol table.
742
+ printWithSpacePadding (Out, NewMembers.size () ? GlobalSymbolOffset : 0 , 20 );
743
+ printWithSpacePadding (
744
+ Out, 0 ,
745
+ 20 ); // Offset to 64 bits global symbol table - Not supported yet
746
+ printWithSpacePadding (
747
+ Out, NewMembers.size () ? sizeof (object::BigArchive::FixLenHdr) : 0 ,
748
+ 20 ); // Offset to first archive member
749
+ printWithSpacePadding (Out, NewMembers.size () ? LastMemberHeaderOffset : 0 ,
750
+ 20 ); // Offset to last archive member
751
+ printWithSpacePadding (
752
+ Out, 0 ,
753
+ 20 ); // Offset to first member of free list - Not supported yet
754
+
755
+ for (const MemberData &M : Data) {
756
+ Out << M.Header << M.Data ;
757
+ if (M.Data .size () % 2 )
758
+ Out << ' \0 ' ;
759
+ }
651
760
761
+ if (NewMembers.size ()) {
762
+ // Member table.
763
+ printBigArchiveMemberHeader (Out, " " , sys::toTimePoint (0 ), 0 , 0 , 0 ,
764
+ MemberTableSize, LastMemberHeaderOffset,
765
+ GlobalSymbolOffset);
766
+ printWithSpacePadding (Out, MemberOffsets.size (), 20 ); // Number of members
767
+ for (uint64_t MemberOffset : MemberOffsets)
768
+ printWithSpacePadding (Out, MemberOffset,
769
+ 20 ); // Offset to member file header.
770
+ for (StringRef MemberName : MemberNames)
771
+ Out << MemberName << ' \0 ' ; // Member file name, null byte padding.
772
+
773
+ if (MemberTableNameStrTblSize % 2 )
774
+ Out << ' \0 ' ; // Name table must be tail padded to an even number of
775
+ // bytes.
776
+
777
+ if (WriteSymtab && NumSyms > 0 )
778
+ writeSymbolTable (Out, Kind, Deterministic, Data, SymNamesBuf,
779
+ LastMemberEndOffset);
780
+ }
781
+ }
652
782
Out.flush ();
653
783
return Error::success ();
654
784
}
0 commit comments