diff --git a/llvm/lib/Object/ArchiveWriter.cpp b/llvm/lib/Object/ArchiveWriter.cpp --- a/llvm/lib/Object/ArchiveWriter.cpp +++ b/llvm/lib/Object/ArchiveWriter.cpp @@ -310,6 +310,7 @@ std::string Header; StringRef Data; StringRef Padding; + uint64_t PreHeadPadSize = 0; }; } // namespace @@ -438,6 +439,38 @@ return (*ObjOrErr)->is64Bit(); } +// In AIX OS, if the member file is an XCOFF object file and has an auxiliary +// header, the content of the member file need to be aligned at the +// MAX(maximum alignment of .text , maximum alignment of .data). +static uint32_t getMemberAlignment(const StringRef &ObjStringRef) { + LLVMContext Context; + MemoryBufferRef ObjMbf(ObjStringRef, ""); + Expected> ObjOrErr = + getSymbolFile(ObjMbf, Context); + + if (!ObjOrErr) { + consumeError(ObjOrErr.takeError()); + return 1; + } + + SymbolicFile *SymObj = ObjOrErr->get(); + if (XCOFFObjectFile *XCOFFObj = dyn_cast_or_null(SymObj)) { + auto GetAuxMaxAlignment = [](auto *AuxHeader) { + if (AuxHeader == nullptr) + return 1; + return 1 << (AuxHeader->MaxAlignOfText > AuxHeader->MaxAlignOfData + ? AuxHeader->MaxAlignOfText + : AuxHeader->MaxAlignOfData); + }; + + if (XCOFFObj->is64Bit()) + return GetAuxMaxAlignment(XCOFFObj->auxiliaryHeader64()); + else + return GetAuxMaxAlignment(XCOFFObj->auxiliaryHeader32()); + } + return 1; +} + static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind, bool Deterministic, ArrayRef Members, StringRef StringTable, unsigned NumSyms, @@ -466,6 +499,7 @@ for (const MemberData &M : Members) { if (isAIXBigArchive(Kind)) { + Pos += M.PreHeadPadSize; Expected Is64BitOrErr = is64BitSymbolicFile(M.Data); // If there is an error, the error will be emit when 'computeMemberData' // call 'getSymbol' function, we use consumeError here. @@ -530,7 +564,7 @@ WriteSymTabType NeedSymbols, ArrayRef NewMembers) { static char PaddingData[8] = {'\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n'}; - + static uint64_t PreMemHeadPadSize = 0; uint64_t Pos = isAIXBigArchive(Kind) ? sizeof(object::BigArchive::FixLenHdr) : 0; @@ -595,11 +629,11 @@ // The big archive format needs to know the offset of the previous member // header. unsigned PrevOffset = 0; - for (const NewArchiveMember &M : NewMembers) { + for (auto M = NewMembers.begin(); M < NewMembers.end(); M++) { std::string Header; raw_string_ostream Out(Header); - MemoryBufferRef Buf = M.Buf->getMemBufferRef(); + MemoryBufferRef Buf = M->Buf->getMemBufferRef(); StringRef Data = Thin ? "" : Buf.getBuffer(); // ld64 expects the members to be 8-byte aligned for 64-bit content and at @@ -615,26 +649,50 @@ sys::TimePoint ModTime; if (UniqueTimestamps) // Increment timestamp for each file of a given name. - ModTime = sys::toTimePoint(FilenameCount[M.MemberName]++); + ModTime = sys::toTimePoint(FilenameCount[M->MemberName]++); else - ModTime = M.ModTime; + ModTime = M->ModTime; uint64_t Size = Buf.getBufferSize() + MemberPadding; if (Size > object::Archive::MaxMemberSize) { std::string StringMsg = - "File " + M.MemberName.str() + " exceeds size limit"; + "File " + M->MemberName.str() + " exceeds size limit"; return make_error( std::move(StringMsg), object::object_error::parse_failed); } if (isAIXBigArchive(Kind)) { - unsigned NextOffset = Pos + sizeof(object::BigArMemHdrType) + - alignTo(M.MemberName.size(), 2) + alignTo(Size, 2); - printBigArchiveMemberHeader(Out, M.MemberName, ModTime, M.UID, M.GID, - M.Perms, Size, PrevOffset, NextOffset); + uint64_t OffsetToMemData = Pos + sizeof(object::BigArMemHdrType) + + alignTo(M->MemberName.size(), 2); + // In big archive, the content of member file need to aligned when the + // member file is xcoff object file which has auxiliary header. + PreMemHeadPadSize = + alignToPowerOf2(OffsetToMemData, getMemberAlignment(Data)) - + OffsetToMemData; + Pos += PreMemHeadPadSize; + + uint64_t NextOffset = Pos + sizeof(object::BigArMemHdrType) + + alignTo(M->MemberName.size(), 2) + alignTo(Size, 2); + + // If there is next member file. we need to calculate the padding before + // the header if there is. + if ((M + 1) != NewMembers.end()) { + uint64_t OffsetToNextMemData = NextOffset + + sizeof(object::BigArMemHdrType) + + alignTo((M + 1)->MemberName.size(), 2); + uint64_t NextMemHeadPadSize = + alignToPowerOf2(OffsetToNextMemData, + getMemberAlignment( + (M + 1)->Buf->getMemBufferRef().getBuffer())) - + OffsetToNextMemData; + NextOffset += NextMemHeadPadSize; + } + + printBigArchiveMemberHeader(Out, M->MemberName, ModTime, M->UID, M->GID, + M->Perms, Size, PrevOffset, NextOffset); PrevOffset = Pos; } else { - printMemberHeader(Out, Pos, StringTable, MemberNames, Kind, Thin, M, + printMemberHeader(Out, Pos, StringTable, MemberNames, Kind, Thin, *M, ModTime, Size); } Out.flush(); @@ -644,12 +702,13 @@ Expected> SymbolsOrErr = getSymbols(Buf, SymNames, HasObject); if (!SymbolsOrErr) - return createFileError(M.MemberName, SymbolsOrErr.takeError()); + return createFileError(M->MemberName, SymbolsOrErr.takeError()); Symbols = std::move(*SymbolsOrErr); } Pos += Header.size() + Data.size() + Padding.size(); - Ret.push_back({std::move(Symbols), std::move(Header), Data, Padding}); + Ret.push_back({std::move(Symbols), std::move(Header), Data, Padding, + PreMemHeadPadSize}); } // If there are no symbols, emit an empty symbol table, to satisfy Solaris // tools, older versions of which expect a symbol table in a non-empty @@ -733,6 +792,7 @@ for (const auto &M : Data) { // Record the start of the member's offset + LastMemberEndOffset += M.PreHeadPadSize; LastMemberHeaderOffset = LastMemberEndOffset; // Account for the size of each part associated with the member. LastMemberEndOffset += M.Header.size() + M.Data.size() + M.Padding.size(); @@ -814,13 +874,14 @@ for (size_t I = 0, Size = NewMembers.size(); I != Size; ++I) { const NewArchiveMember &Member = NewMembers[I]; MemberTableNameStrTblSize += Member.MemberName.size() + 1; + MemberEndOffset += Data[I].PreHeadPadSize; MemberOffsets.push_back(MemberEndOffset); MemberNames.push_back(Member.MemberName); // File member name ended with "`\n". The length is included in // BigArMemHdrType. MemberEndOffset += sizeof(object::BigArMemHdrType) + - alignTo(Data[I].Data.size(), 2) + - alignTo(Member.MemberName.size(), 2); + alignTo(Data[I].Data.size(), 2) + + alignTo(Member.MemberName.size(), 2); } // AIX member table size. @@ -883,9 +944,12 @@ // symbol table. printWithSpacePadding(Out, NewMembers.size() ? GlobalSymbolOffset : 0, 20); printWithSpacePadding(Out, GlobalSymbolOffset64, 20); - printWithSpacePadding( - Out, NewMembers.size() ? sizeof(object::BigArchive::FixLenHdr) : 0, - 20); // Offset to first archive member + printWithSpacePadding(Out, + NewMembers.size() + ? sizeof(object::BigArchive::FixLenHdr) + + Data[0].PreHeadPadSize + : 0, + 20); // Offset to first archive member printWithSpacePadding(Out, NewMembers.size() ? LastMemberHeaderOffset : 0, 20); // Offset to last archive member printWithSpacePadding( @@ -893,6 +957,8 @@ 20); // Offset to first member of free list - Not supported yet for (const MemberData &M : Data) { + for (uint64_t i = 0; i < M.PreHeadPadSize; i++) + Out << '\0'; Out << M.Header << M.Data; if (M.Data.size() % 2) Out << '\0'; diff --git a/llvm/test/tools/llvm-ar/big-archive-xcoff-auxi-head-align.test b/llvm/test/tools/llvm-ar/big-archive-xcoff-auxi-head-align.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-ar/big-archive-xcoff-auxi-head-align.test @@ -0,0 +1,16 @@ +## Test the content of xcoff object file which has auxiliary header +## is aligned in big archive basesd on the +## MAX(maxinum aligment of .text, maxinum alignment of .data). + +# RUN: rm -rf %t && mkdir %t +# RUN: cp %p/../llvm-readobj/XCOFF/Inputs/needed-libs*.o %t +# RUN: cd %t +# RUN: env OBJECT_MODE=32_64 llvm-ar -q t1.a needed-libs-64.o needed-libs-32.o +# RUN: env OBJECT_MODE=32_64 llvm-ar -q t2.a needed-libs-32.o needed-libs-64.o +# RUN: %python -c 'f=open("t1.a","rb");f.seek(384);print(f.read(2));f.close()' | FileCheck -check-prefix=MAGIC64 %s +# RUN: %python -c 'f=open("t1.a","rb");f.seek(7296);print(f.read(2));f.close()' | FileCheck -check-prefix=MAGIC32 %s +# RUN: %python -c 'f=open("t2.a","rb");f.seek(384);print(f.read(2));f.close()' | FileCheck -check-prefix=MAGIC32 %s +# RUN: %python -c 'f=open("t2.a","rb");f.seek(6144);print(f.read(2));f.close()' | FileCheck -check-prefix=MAGIC64 %s + +# MAGIC64: b'\x01\xf7' +# MAGIC32: b'\x01\xdf'