@@ -331,6 +331,8 @@ struct MemberData {
331
331
std::string Header;
332
332
StringRef Data;
333
333
StringRef Padding;
334
+ uint64_t PreHeadPadSize = 0 ;
335
+ std::unique_ptr<SymbolicFile> SymFile = nullptr ;
334
336
};
335
337
} // namespace
336
338
@@ -496,21 +498,66 @@ getSymbolicFile(MemoryBufferRef Buf, LLVMContext &Context) {
496
498
}
497
499
}
498
500
499
- static Expected<bool > is64BitSymbolicFile (const StringRef &ObjStringRef) {
500
- MemoryBufferRef ObjMbf (ObjStringRef, " " );
501
- // In the scenario when LLVMContext is populated SymbolicFile will contain a
502
- // reference to it, thus SymbolicFile should be destroyed first.
503
- LLVMContext Context;
504
- Expected<std::unique_ptr<SymbolicFile>> ObjOrErr =
505
- getSymbolicFile (ObjMbf, Context);
506
- if (!ObjOrErr)
507
- return ObjOrErr.takeError ();
501
+ static bool is64BitSymbolicFile (const SymbolicFile *SymObj) {
502
+ return SymObj != nullptr ? SymObj->is64Bit () : false ;
503
+ }
508
504
509
- // Treat non-symbolic file types as not 64-bits.
510
- if (!*ObjOrErr)
511
- return false ;
505
+ // Log2 of PAGESIZE(4096) on an AIX system.
506
+ static const uint32_t Log2OfAIXPageSize = 12 ;
507
+
508
+ // In the AIX big archive format, since the data content follows the member file
509
+ // name, if the name ends on an odd byte, an extra byte will be added for
510
+ // padding. This ensures that the data within the member file starts at an even
511
+ // byte.
512
+ static const uint32_t MinBigArchiveMemDataAlign = 2 ;
513
+
514
+ template <typename AuxiliaryHeader>
515
+ uint16_t getAuxMaxAlignment (uint16_t AuxHeaderSize, AuxiliaryHeader *AuxHeader,
516
+ uint16_t Log2OfMaxAlign) {
517
+ // If the member doesn't have an auxiliary header, it isn't a loadable object
518
+ // and so it just needs aligning at the minimum value.
519
+ if (AuxHeader == nullptr )
520
+ return MinBigArchiveMemDataAlign;
521
+
522
+ // If the auxiliary header does not have both MaxAlignOfData and
523
+ // MaxAlignOfText field, it is not a loadable shared object file, so align at
524
+ // the minimum value. The 'ModuleType' member is located right after
525
+ // 'MaxAlignOfData' in the AuxiliaryHeader.
526
+ if (AuxHeaderSize < offsetof (AuxiliaryHeader, ModuleType))
527
+ return MinBigArchiveMemDataAlign;
528
+
529
+ // If the XCOFF object file does not have a loader section, it is not
530
+ // loadable, so align at the minimum value.
531
+ if (AuxHeader->SecNumOfLoader == 0 )
532
+ return MinBigArchiveMemDataAlign;
533
+
534
+ // The content of the loadable member file needs to be aligned at MAX(maximum
535
+ // alignment of .text, maximum alignment of .data) if there are both fields.
536
+ // If the desired alignment is > PAGESIZE, 32-bit members are aligned on a
537
+ // word boundary, while 64-bit members are aligned on a PAGESIZE(2^12=4096)
538
+ // boundary.
539
+ uint16_t Log2OfAlign =
540
+ std::max (AuxHeader->MaxAlignOfText , AuxHeader->MaxAlignOfData );
541
+ return 1 << (Log2OfAlign > Log2OfAIXPageSize ? Log2OfMaxAlign : Log2OfAlign);
542
+ }
512
543
513
- return (*ObjOrErr)->is64Bit ();
544
+ // AIX big archives may contain shared object members. The AIX OS requires these
545
+ // members to be aligned if they are 64-bit and recommends it for 32-bit
546
+ // members. This ensures that when these members are loaded they are aligned in
547
+ // memory.
548
+ static uint32_t getMemberAlignment (SymbolicFile *SymObj) {
549
+ XCOFFObjectFile *XCOFFObj = dyn_cast_or_null<XCOFFObjectFile>(SymObj);
550
+ if (!XCOFFObj)
551
+ return MinBigArchiveMemDataAlign;
552
+
553
+ // If the desired alignment is > PAGESIZE, 32-bit members are aligned on a
554
+ // word boundary, while 64-bit members are aligned on a PAGESIZE boundary.
555
+ return XCOFFObj->is64Bit ()
556
+ ? getAuxMaxAlignment (XCOFFObj->fileHeader64 ()->AuxHeaderSize ,
557
+ XCOFFObj->auxiliaryHeader64 (),
558
+ Log2OfAIXPageSize)
559
+ : getAuxMaxAlignment (XCOFFObj->fileHeader32 ()->AuxHeaderSize ,
560
+ XCOFFObj->auxiliaryHeader32 (), 2 );
514
561
}
515
562
516
563
static void writeSymbolTable (raw_ostream &Out, object::Archive::Kind Kind,
@@ -539,13 +586,8 @@ static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind,
539
586
uint64_t Pos = MembersOffset;
540
587
for (const MemberData &M : Members) {
541
588
if (isAIXBigArchive (Kind)) {
542
- Expected<bool > Is64BitOrErr = is64BitSymbolicFile (M.Data );
543
- // If there is an error, the error will have been emitted when
544
- // 'computeMemberData' called the 'getSymbol' function, so don't need to
545
- // handle it here.
546
- if (!Is64BitOrErr)
547
- cantFail (Is64BitOrErr.takeError ());
548
- if (*Is64BitOrErr != Is64Bit) {
589
+ Pos += M.PreHeadPadSize ;
590
+ if (is64BitSymbolicFile (M.SymFile .get ()) != Is64Bit) {
549
591
Pos += M.Header .size () + M.Data .size () + M.Padding .size ();
550
592
continue ;
551
593
}
@@ -629,29 +671,19 @@ static bool isECObject(object::SymbolicFile &Obj) {
629
671
return false ;
630
672
}
631
673
632
- static Expected<std::vector<unsigned >>
633
- getSymbols (MemoryBufferRef Buf, uint16_t Index, raw_ostream &SymNames,
634
- SymMap *SymMap, bool &HasObject) {
635
- // In the scenario when LLVMContext is populated SymbolicFile will contain a
636
- // reference to it, thus SymbolicFile should be destroyed first.
637
- LLVMContext Context;
638
-
674
+ static Expected<std::vector<unsigned >> getSymbols (SymbolicFile *Obj,
675
+ uint16_t Index,
676
+ raw_ostream &SymNames,
677
+ SymMap *SymMap) {
639
678
std::vector<unsigned > Ret;
640
- Expected<std::unique_ptr<SymbolicFile>> ObjOrErr =
641
- getSymbolicFile (Buf, Context);
642
- if (!ObjOrErr)
643
- return ObjOrErr.takeError ();
644
679
645
- // If the member is non-symbolic file, treat it as having no symbols.
646
- if (!*ObjOrErr)
680
+ if (Obj == nullptr )
647
681
return Ret;
648
682
649
- std::unique_ptr<object::SymbolicFile> Obj = std::move (*ObjOrErr);
650
-
651
683
std::map<std::string, uint16_t > *Map = nullptr ;
652
684
if (SymMap)
653
685
Map = SymMap->UseECMap && isECObject (*Obj) ? &SymMap->ECMap : &SymMap->Map ;
654
- HasObject = true ;
686
+
655
687
for (const object::BasicSymbolRef &S : Obj->symbols ()) {
656
688
if (!isArchiveSymbol (S))
657
689
continue ;
@@ -681,9 +713,9 @@ static Expected<std::vector<MemberData>>
681
713
computeMemberData (raw_ostream &StringTable, raw_ostream &SymNames,
682
714
object::Archive::Kind Kind, bool Thin, bool Deterministic,
683
715
SymtabWritingMode NeedSymbols, SymMap *SymMap,
684
- ArrayRef<NewArchiveMember> NewMembers) {
716
+ LLVMContext &Context, ArrayRef<NewArchiveMember> NewMembers) {
685
717
static char PaddingData[8 ] = {' \n ' , ' \n ' , ' \n ' , ' \n ' , ' \n ' , ' \n ' , ' \n ' , ' \n ' };
686
-
718
+ uint64_t MemHeadPadSize = 0 ;
687
719
uint64_t Pos =
688
720
isAIXBigArchive (Kind) ? sizeof (object::BigArchive::FixLenHdr) : 0 ;
689
721
@@ -748,12 +780,16 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
748
780
// The big archive format needs to know the offset of the previous member
749
781
// header.
750
782
uint64_t PrevOffset = 0 ;
783
+ uint64_t NextMemHeadPadSize = 0 ;
784
+ std::unique_ptr<SymbolicFile> CurSymFile;
785
+ std::unique_ptr<SymbolicFile> NextSymFile;
751
786
uint16_t Index = 0 ;
752
- for (const NewArchiveMember &M : NewMembers) {
787
+
788
+ for (auto M = NewMembers.begin (); M < NewMembers.end (); ++M) {
753
789
std::string Header;
754
790
raw_string_ostream Out (Header);
755
791
756
- MemoryBufferRef Buf = M. Buf ->getMemBufferRef ();
792
+ MemoryBufferRef Buf = M-> Buf ->getMemBufferRef ();
757
793
StringRef Data = Thin ? " " : Buf.getBuffer ();
758
794
759
795
Index++;
@@ -771,41 +807,94 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
771
807
sys::TimePoint<std::chrono::seconds> ModTime;
772
808
if (UniqueTimestamps)
773
809
// Increment timestamp for each file of a given name.
774
- ModTime = sys::toTimePoint (FilenameCount[M. MemberName ]++);
810
+ ModTime = sys::toTimePoint (FilenameCount[M-> MemberName ]++);
775
811
else
776
- ModTime = M. ModTime ;
812
+ ModTime = M-> ModTime ;
777
813
778
814
uint64_t Size = Buf.getBufferSize () + MemberPadding;
779
815
if (Size > object::Archive::MaxMemberSize) {
780
816
std::string StringMsg =
781
- " File " + M. MemberName .str () + " exceeds size limit" ;
817
+ " File " + M-> MemberName .str () + " exceeds size limit" ;
782
818
return make_error<object::GenericBinaryError>(
783
819
std::move (StringMsg), object::object_error::parse_failed);
784
820
}
785
821
822
+ if (NeedSymbols != SymtabWritingMode::NoSymtab || isAIXBigArchive (Kind)) {
823
+ auto SetNextSymFile = [&NextSymFile,
824
+ &Context](MemoryBufferRef Buf,
825
+ StringRef MemberName) -> Error {
826
+ Expected<std::unique_ptr<SymbolicFile>> SymFileOrErr =
827
+ getSymbolicFile (Buf, Context);
828
+ if (!SymFileOrErr)
829
+ return createFileError (MemberName, SymFileOrErr.takeError ());
830
+ NextSymFile = std::move (*SymFileOrErr);
831
+ return Error::success ();
832
+ };
833
+
834
+ if (M == NewMembers.begin ())
835
+ if (Error Err = SetNextSymFile (Buf, M->MemberName ))
836
+ return std::move (Err);
837
+
838
+ CurSymFile = std::move (NextSymFile);
839
+
840
+ if ((M + 1 ) != NewMembers.end ())
841
+ if (Error Err = SetNextSymFile ((M + 1 )->Buf ->getMemBufferRef (),
842
+ (M + 1 )->MemberName ))
843
+ return std::move (Err);
844
+ }
845
+
846
+ // In the big archive file format, we need to calculate and include the next
847
+ // member offset and previous member offset in the file member header.
786
848
if (isAIXBigArchive (Kind)) {
849
+ uint64_t OffsetToMemData = Pos + sizeof (object::BigArMemHdrType) +
850
+ alignTo (M->MemberName .size (), 2 );
851
+
852
+ if (M == NewMembers.begin ())
853
+ NextMemHeadPadSize =
854
+ alignToPowerOf2 (OffsetToMemData,
855
+ getMemberAlignment (CurSymFile.get ())) -
856
+ OffsetToMemData;
857
+
858
+ MemHeadPadSize = NextMemHeadPadSize;
859
+ Pos += MemHeadPadSize;
787
860
uint64_t NextOffset = Pos + sizeof (object::BigArMemHdrType) +
788
- alignTo (M.MemberName .size (), 2 ) + alignTo (Size, 2 );
789
- printBigArchiveMemberHeader (Out, M.MemberName , ModTime, M.UID , M.GID ,
790
- M.Perms , Size, PrevOffset, NextOffset);
861
+ alignTo (M->MemberName .size (), 2 ) + alignTo (Size, 2 );
862
+
863
+ // If there is another member file after this, we need to calculate the
864
+ // padding before the header.
865
+ if ((M + 1 ) != NewMembers.end ()) {
866
+ uint64_t OffsetToNextMemData = NextOffset +
867
+ sizeof (object::BigArMemHdrType) +
868
+ alignTo ((M + 1 )->MemberName .size (), 2 );
869
+ NextMemHeadPadSize =
870
+ alignToPowerOf2 (OffsetToNextMemData,
871
+ getMemberAlignment (NextSymFile.get ())) -
872
+ OffsetToNextMemData;
873
+ NextOffset += NextMemHeadPadSize;
874
+ }
875
+ printBigArchiveMemberHeader (Out, M->MemberName , ModTime, M->UID , M->GID ,
876
+ M->Perms , Size, PrevOffset, NextOffset);
791
877
PrevOffset = Pos;
792
878
} else {
793
- printMemberHeader (Out, Pos, StringTable, MemberNames, Kind, Thin, M,
879
+ printMemberHeader (Out, Pos, StringTable, MemberNames, Kind, Thin, * M,
794
880
ModTime, Size);
795
881
}
796
882
Out.flush ();
797
883
798
884
std::vector<unsigned > Symbols;
799
885
if (NeedSymbols != SymtabWritingMode::NoSymtab) {
800
886
Expected<std::vector<unsigned >> SymbolsOrErr =
801
- getSymbols (Buf , Index, SymNames, SymMap, HasObject );
887
+ getSymbols (CurSymFile. get () , Index, SymNames, SymMap);
802
888
if (!SymbolsOrErr)
803
- return createFileError (M. MemberName , SymbolsOrErr.takeError ());
889
+ return createFileError (M-> MemberName , SymbolsOrErr.takeError ());
804
890
Symbols = std::move (*SymbolsOrErr);
891
+ if (CurSymFile)
892
+ HasObject = true ;
805
893
}
806
894
807
895
Pos += Header.size () + Data.size () + Padding.size ();
808
- Ret.push_back ({std::move (Symbols), std::move (Header), Data, Padding});
896
+ Ret.push_back ({std::move (Symbols), std::move (Header), Data, Padding,
897
+ MemHeadPadSize, std::move (CurSymFile)});
809
898
}
810
899
// If there are no symbols, emit an empty symbol table, to satisfy Solaris
811
900
// tools, older versions of which expect a symbol table in a non-empty
@@ -876,10 +965,14 @@ static Error writeArchiveToStream(raw_ostream &Out,
876
965
if (isCOFFArchive (Kind) && NewMembers.size () > 0xfffe )
877
966
Kind = object::Archive::K_GNU;
878
967
968
+ // In the scenario when LLVMContext is populated SymbolicFile will contain a
969
+ // reference to it, thus SymbolicFile should be destroyed first.
970
+ LLVMContext Context;
971
+
879
972
SymMap.UseECMap = IsEC;
880
973
Expected<std::vector<MemberData>> DataOrErr = computeMemberData (
881
974
StringTable, SymNames, Kind, Thin, Deterministic, WriteSymtab,
882
- isCOFFArchive (Kind) ? &SymMap : nullptr , NewMembers);
975
+ isCOFFArchive (Kind) ? &SymMap : nullptr , Context, NewMembers);
883
976
if (Error E = DataOrErr.takeError ())
884
977
return E;
885
978
std::vector<MemberData> &Data = *DataOrErr;
@@ -902,6 +995,7 @@ static Error writeArchiveToStream(raw_ostream &Out,
902
995
903
996
for (const auto &M : Data) {
904
997
// Record the start of the member's offset
998
+ LastMemberEndOffset += M.PreHeadPadSize ;
905
999
LastMemberHeaderOffset = LastMemberEndOffset;
906
1000
// Account for the size of each part associated with the member.
907
1001
LastMemberEndOffset += M.Header .size () + M.Data .size () + M.Padding .size ();
@@ -913,13 +1007,9 @@ static Error writeArchiveToStream(raw_ostream &Out,
913
1007
// members. As a big archive can have both 32-bit and 64-bit file members,
914
1008
// we need to know the number of symbols in each symbol table individually.
915
1009
if (isAIXBigArchive (Kind) && ShouldWriteSymtab) {
916
- Expected<bool > Is64BitOrErr = is64BitSymbolicFile (M.Data );
917
- if (Error E = Is64BitOrErr.takeError ())
918
- return E;
919
-
920
- if (!*Is64BitOrErr)
921
- NumSyms32 += M.Symbols .size ();
922
- }
1010
+ if (!is64BitSymbolicFile (M.SymFile .get ()))
1011
+ NumSyms32 += M.Symbols .size ();
1012
+ }
923
1013
}
924
1014
925
1015
std::optional<uint64_t > HeadersSize;
@@ -1000,13 +1090,14 @@ static Error writeArchiveToStream(raw_ostream &Out,
1000
1090
for (size_t I = 0 , Size = NewMembers.size (); I != Size; ++I) {
1001
1091
const NewArchiveMember &Member = NewMembers[I];
1002
1092
MemberTableNameStrTblSize += Member.MemberName .size () + 1 ;
1093
+ MemberEndOffset += Data[I].PreHeadPadSize ;
1003
1094
MemberOffsets.push_back (MemberEndOffset);
1004
1095
MemberNames.push_back (Member.MemberName );
1005
1096
// File member name ended with "`\n". The length is included in
1006
1097
// BigArMemHdrType.
1007
1098
MemberEndOffset += sizeof (object::BigArMemHdrType) +
1008
- alignTo (Data[I].Data .size (), 2 ) +
1009
- alignTo (Member.MemberName .size (), 2 );
1099
+ alignTo (Data[I].Data .size (), 2 ) +
1100
+ alignTo (Member.MemberName .size (), 2 );
1010
1101
}
1011
1102
1012
1103
// AIX member table size.
@@ -1021,16 +1112,11 @@ static Error writeArchiveToStream(raw_ostream &Out,
1021
1112
1022
1113
if (ShouldWriteSymtab && NumSyms)
1023
1114
// Generate the symbol names for the members.
1024
- for (const NewArchiveMember &M : NewMembers) {
1025
- MemoryBufferRef Buf = M.Buf ->getMemBufferRef ();
1026
- Expected<bool > Is64BitOrErr = is64BitSymbolicFile (Buf.getBuffer ());
1027
- if (!Is64BitOrErr)
1028
- return Is64BitOrErr.takeError ();
1029
-
1030
- bool HasObject;
1031
- Expected<std::vector<unsigned >> SymbolsOrErr =
1032
- getSymbols (Buf, 0 , *Is64BitOrErr ? SymNames64 : SymNames32, nullptr ,
1033
- HasObject);
1115
+ for (const auto &M : Data) {
1116
+ Expected<std::vector<unsigned >> SymbolsOrErr = getSymbols (
1117
+ M.SymFile .get (), 0 ,
1118
+ is64BitSymbolicFile (M.SymFile .get ()) ? SymNames64 : SymNames32,
1119
+ nullptr );
1034
1120
if (!SymbolsOrErr)
1035
1121
return SymbolsOrErr.takeError ();
1036
1122
}
@@ -1069,16 +1155,20 @@ static Error writeArchiveToStream(raw_ostream &Out,
1069
1155
// symbol table.
1070
1156
printWithSpacePadding (Out, GlobalSymbolOffset, 20 );
1071
1157
printWithSpacePadding (Out, GlobalSymbolOffset64, 20 );
1072
- printWithSpacePadding (
1073
- Out, NewMembers.size () ? sizeof (object::BigArchive::FixLenHdr) : 0 ,
1074
- 20 ); // Offset to first archive member
1158
+ printWithSpacePadding (Out,
1159
+ NewMembers.size ()
1160
+ ? sizeof (object::BigArchive::FixLenHdr) +
1161
+ Data[0 ].PreHeadPadSize
1162
+ : 0 ,
1163
+ 20 ); // Offset to first archive member
1075
1164
printWithSpacePadding (Out, NewMembers.size () ? LastMemberHeaderOffset : 0 ,
1076
1165
20 ); // Offset to last archive member
1077
1166
printWithSpacePadding (
1078
1167
Out, 0 ,
1079
1168
20 ); // Offset to first member of free list - Not supported yet
1080
1169
1081
1170
for (const MemberData &M : Data) {
1171
+ Out << std::string (M.PreHeadPadSize , ' \0 ' );
1082
1172
Out << M.Header << M.Data ;
1083
1173
if (M.Data .size () % 2 )
1084
1174
Out << ' \0 ' ;
0 commit comments