diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2023-12-18 20:30:12 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2024-04-06 20:11:55 +0000 |
commit | 5f757f3ff9144b609b3c433dfd370cc6bdc191ad (patch) | |
tree | 1b4e980b866cd26a00af34c0a653eb640bd09caf /contrib/llvm-project/llvm/lib/Object/ArchiveWriter.cpp | |
parent | 3e1c8a35f741a5d114d0ba670b15191355711fe9 (diff) | |
parent | 312c0ed19cc5276a17bacf2120097bec4515b0f1 (diff) |
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Object/ArchiveWriter.cpp')
-rw-r--r-- | contrib/llvm-project/llvm/lib/Object/ArchiveWriter.cpp | 286 |
1 files changed, 194 insertions, 92 deletions
diff --git a/contrib/llvm-project/llvm/lib/Object/ArchiveWriter.cpp b/contrib/llvm-project/llvm/lib/Object/ArchiveWriter.cpp index d79a5c6bef30..2f70c9edd13e 100644 --- a/contrib/llvm-project/llvm/lib/Object/ArchiveWriter.cpp +++ b/contrib/llvm-project/llvm/lib/Object/ArchiveWriter.cpp @@ -18,6 +18,7 @@ #include "llvm/IR/LLVMContext.h" #include "llvm/Object/Archive.h" #include "llvm/Object/COFF.h" +#include "llvm/Object/COFFImportFile.h" #include "llvm/Object/Error.h" #include "llvm/Object/IRObjectFile.h" #include "llvm/Object/MachO.h" @@ -202,11 +203,12 @@ static bool isBSDLike(object::Archive::Kind Kind) { template <class T> static void print(raw_ostream &Out, object::Archive::Kind Kind, T Val) { support::endian::write(Out, Val, - isBSDLike(Kind) ? support::little : support::big); + isBSDLike(Kind) ? llvm::endianness::little + : llvm::endianness::big); } template <class T> static void printLE(raw_ostream &Out, T Val) { - support::endian::write(Out, Val, support::little); + support::endian::write(Out, Val, llvm::endianness::little); } static void printRestOfMemberHeader( @@ -331,6 +333,8 @@ struct MemberData { std::string Header; StringRef Data; StringRef Padding; + uint64_t PreHeadPadSize = 0; + std::unique_ptr<SymbolicFile> SymFile = nullptr; }; } // namespace @@ -496,21 +500,66 @@ getSymbolicFile(MemoryBufferRef Buf, LLVMContext &Context) { } } -static Expected<bool> is64BitSymbolicFile(const StringRef &ObjStringRef) { - MemoryBufferRef ObjMbf(ObjStringRef, ""); - // In the scenario when LLVMContext is populated SymbolicFile will contain a - // reference to it, thus SymbolicFile should be destroyed first. - LLVMContext Context; - Expected<std::unique_ptr<SymbolicFile>> ObjOrErr = - getSymbolicFile(ObjMbf, Context); - if (!ObjOrErr) - return ObjOrErr.takeError(); +static bool is64BitSymbolicFile(const SymbolicFile *SymObj) { + return SymObj != nullptr ? SymObj->is64Bit() : false; +} - // Treat non-symbolic file types as not 64-bits. - if (!*ObjOrErr) - return false; +// Log2 of PAGESIZE(4096) on an AIX system. +static const uint32_t Log2OfAIXPageSize = 12; + +// In the AIX big archive format, since the data content follows the member file +// name, if the name ends on an odd byte, an extra byte will be added for +// padding. This ensures that the data within the member file starts at an even +// byte. +static const uint32_t MinBigArchiveMemDataAlign = 2; + +template <typename AuxiliaryHeader> +uint16_t getAuxMaxAlignment(uint16_t AuxHeaderSize, AuxiliaryHeader *AuxHeader, + uint16_t Log2OfMaxAlign) { + // If the member doesn't have an auxiliary header, it isn't a loadable object + // and so it just needs aligning at the minimum value. + if (AuxHeader == nullptr) + return MinBigArchiveMemDataAlign; + + // If the auxiliary header does not have both MaxAlignOfData and + // MaxAlignOfText field, it is not a loadable shared object file, so align at + // the minimum value. The 'ModuleType' member is located right after + // 'MaxAlignOfData' in the AuxiliaryHeader. + if (AuxHeaderSize < offsetof(AuxiliaryHeader, ModuleType)) + return MinBigArchiveMemDataAlign; + + // If the XCOFF object file does not have a loader section, it is not + // loadable, so align at the minimum value. + if (AuxHeader->SecNumOfLoader == 0) + return MinBigArchiveMemDataAlign; + + // The content of the loadable member file needs to be aligned at MAX(maximum + // alignment of .text, maximum alignment of .data) if there are both fields. + // If the desired alignment is > PAGESIZE, 32-bit members are aligned on a + // word boundary, while 64-bit members are aligned on a PAGESIZE(2^12=4096) + // boundary. + uint16_t Log2OfAlign = + std::max(AuxHeader->MaxAlignOfText, AuxHeader->MaxAlignOfData); + return 1 << (Log2OfAlign > Log2OfAIXPageSize ? Log2OfMaxAlign : Log2OfAlign); +} - return (*ObjOrErr)->is64Bit(); +// AIX big archives may contain shared object members. The AIX OS requires these +// members to be aligned if they are 64-bit and recommends it for 32-bit +// members. This ensures that when these members are loaded they are aligned in +// memory. +static uint32_t getMemberAlignment(SymbolicFile *SymObj) { + XCOFFObjectFile *XCOFFObj = dyn_cast_or_null<XCOFFObjectFile>(SymObj); + if (!XCOFFObj) + return MinBigArchiveMemDataAlign; + + // If the desired alignment is > PAGESIZE, 32-bit members are aligned on a + // word boundary, while 64-bit members are aligned on a PAGESIZE boundary. + return XCOFFObj->is64Bit() + ? getAuxMaxAlignment(XCOFFObj->fileHeader64()->AuxHeaderSize, + XCOFFObj->auxiliaryHeader64(), + Log2OfAIXPageSize) + : getAuxMaxAlignment(XCOFFObj->fileHeader32()->AuxHeaderSize, + XCOFFObj->auxiliaryHeader32(), 2); } static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind, @@ -539,13 +588,8 @@ static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind, uint64_t Pos = MembersOffset; for (const MemberData &M : Members) { if (isAIXBigArchive(Kind)) { - Expected<bool> Is64BitOrErr = is64BitSymbolicFile(M.Data); - // If there is an error, the error will have been emitted when - // 'computeMemberData' called the 'getSymbol' function, so don't need to - // handle it here. - if (!Is64BitOrErr) - cantFail(Is64BitOrErr.takeError()); - if (*Is64BitOrErr != Is64Bit) { + Pos += M.PreHeadPadSize; + if (is64BitSymbolicFile(M.SymFile.get()) != Is64Bit) { Pos += M.Header.size() + M.Data.size() + M.Padding.size(); continue; } @@ -617,6 +661,10 @@ static bool isECObject(object::SymbolicFile &Obj) { return cast<llvm::object::COFFObjectFile>(&Obj)->getMachine() != COFF::IMAGE_FILE_MACHINE_ARM64; + if (Obj.isCOFFImportFile()) + return cast<llvm::object::COFFImportFile>(&Obj)->getMachine() != + COFF::IMAGE_FILE_MACHINE_ARM64; + if (Obj.isIR()) { Expected<std::string> TripleStr = getBitcodeTargetTriple(Obj.getMemoryBufferRef()); @@ -629,29 +677,19 @@ static bool isECObject(object::SymbolicFile &Obj) { return false; } -static Expected<std::vector<unsigned>> -getSymbols(MemoryBufferRef Buf, uint16_t Index, raw_ostream &SymNames, - SymMap *SymMap, bool &HasObject) { - // In the scenario when LLVMContext is populated SymbolicFile will contain a - // reference to it, thus SymbolicFile should be destroyed first. - LLVMContext Context; - +static Expected<std::vector<unsigned>> getSymbols(SymbolicFile *Obj, + uint16_t Index, + raw_ostream &SymNames, + SymMap *SymMap) { std::vector<unsigned> Ret; - Expected<std::unique_ptr<SymbolicFile>> ObjOrErr = - getSymbolicFile(Buf, Context); - if (!ObjOrErr) - return ObjOrErr.takeError(); - // If the member is non-symbolic file, treat it as having no symbols. - if (!*ObjOrErr) + if (Obj == nullptr) return Ret; - std::unique_ptr<object::SymbolicFile> Obj = std::move(*ObjOrErr); - std::map<std::string, uint16_t> *Map = nullptr; if (SymMap) Map = SymMap->UseECMap && isECObject(*Obj) ? &SymMap->ECMap : &SymMap->Map; - HasObject = true; + for (const object::BasicSymbolRef &S : Obj->symbols()) { if (!isArchiveSymbol(S)) continue; @@ -680,10 +718,10 @@ getSymbols(MemoryBufferRef Buf, uint16_t Index, raw_ostream &SymNames, static Expected<std::vector<MemberData>> computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames, object::Archive::Kind Kind, bool Thin, bool Deterministic, - bool NeedSymbols, SymMap *SymMap, - ArrayRef<NewArchiveMember> NewMembers) { + SymtabWritingMode NeedSymbols, SymMap *SymMap, + LLVMContext &Context, ArrayRef<NewArchiveMember> NewMembers) { static char PaddingData[8] = {'\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n'}; - + uint64_t MemHeadPadSize = 0; uint64_t Pos = isAIXBigArchive(Kind) ? sizeof(object::BigArchive::FixLenHdr) : 0; @@ -698,7 +736,7 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames, // UniqueTimestamps is a special case to improve debugging on Darwin: // // The Darwin linker does not link debug info into the final - // binary. Instead, it emits entries of type N_OSO in in the output + // binary. Instead, it emits entries of type N_OSO in the output // binary's symbol table, containing references to the linked-in // object files. Using that reference, the debugger can read the // debug data directly from the object files. Alternatively, an @@ -748,12 +786,16 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames, // The big archive format needs to know the offset of the previous member // header. uint64_t PrevOffset = 0; + uint64_t NextMemHeadPadSize = 0; + std::unique_ptr<SymbolicFile> CurSymFile; + std::unique_ptr<SymbolicFile> NextSymFile; uint16_t Index = 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(); Index++; @@ -771,48 +813,101 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames, sys::TimePoint<std::chrono::seconds> 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<object::GenericBinaryError>( std::move(StringMsg), object::object_error::parse_failed); } + if (NeedSymbols != SymtabWritingMode::NoSymtab || isAIXBigArchive(Kind)) { + auto SetNextSymFile = [&NextSymFile, + &Context](MemoryBufferRef Buf, + StringRef MemberName) -> Error { + Expected<std::unique_ptr<SymbolicFile>> SymFileOrErr = + getSymbolicFile(Buf, Context); + if (!SymFileOrErr) + return createFileError(MemberName, SymFileOrErr.takeError()); + NextSymFile = std::move(*SymFileOrErr); + return Error::success(); + }; + + if (M == NewMembers.begin()) + if (Error Err = SetNextSymFile(Buf, M->MemberName)) + return std::move(Err); + + CurSymFile = std::move(NextSymFile); + + if ((M + 1) != NewMembers.end()) + if (Error Err = SetNextSymFile((M + 1)->Buf->getMemBufferRef(), + (M + 1)->MemberName)) + return std::move(Err); + } + + // In the big archive file format, we need to calculate and include the next + // member offset and previous member offset in the file member header. if (isAIXBigArchive(Kind)) { + uint64_t OffsetToMemData = Pos + sizeof(object::BigArMemHdrType) + + alignTo(M->MemberName.size(), 2); + + if (M == NewMembers.begin()) + NextMemHeadPadSize = + alignToPowerOf2(OffsetToMemData, + getMemberAlignment(CurSymFile.get())) - + OffsetToMemData; + + MemHeadPadSize = NextMemHeadPadSize; + Pos += MemHeadPadSize; uint64_t 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); + alignTo(M->MemberName.size(), 2) + alignTo(Size, 2); + + // If there is another member file after this, we need to calculate the + // padding before the header. + if ((M + 1) != NewMembers.end()) { + uint64_t OffsetToNextMemData = NextOffset + + sizeof(object::BigArMemHdrType) + + alignTo((M + 1)->MemberName.size(), 2); + NextMemHeadPadSize = + alignToPowerOf2(OffsetToNextMemData, + getMemberAlignment(NextSymFile.get())) - + 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(); std::vector<unsigned> Symbols; - if (NeedSymbols) { + if (NeedSymbols != SymtabWritingMode::NoSymtab) { Expected<std::vector<unsigned>> SymbolsOrErr = - getSymbols(Buf, Index, SymNames, SymMap, HasObject); + getSymbols(CurSymFile.get(), Index, SymNames, SymMap); if (!SymbolsOrErr) - return createFileError(M.MemberName, SymbolsOrErr.takeError()); + return createFileError(M->MemberName, SymbolsOrErr.takeError()); Symbols = std::move(*SymbolsOrErr); + if (CurSymFile) + HasObject = true; } 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, + MemHeadPadSize, std::move(CurSymFile)}); } // 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 // archive, regardless of whether there are any symbols in it. if (HasObject && SymNames.tell() == 0 && !isCOFFArchive(Kind)) SymNames << '\0' << '\0' << '\0'; - return Ret; + return std::move(Ret); } namespace llvm { @@ -860,7 +955,8 @@ Expected<std::string> computeArchiveRelativePath(StringRef From, StringRef To) { static Error writeArchiveToStream(raw_ostream &Out, ArrayRef<NewArchiveMember> NewMembers, - bool WriteSymtab, object::Archive::Kind Kind, + SymtabWritingMode WriteSymtab, + object::Archive::Kind Kind, bool Deterministic, bool Thin, bool IsEC) { assert((!Thin || !isBSDLike(Kind)) && "Only the gnu format has a thin mode"); @@ -875,10 +971,14 @@ static Error writeArchiveToStream(raw_ostream &Out, if (isCOFFArchive(Kind) && NewMembers.size() > 0xfffe) Kind = object::Archive::K_GNU; + // In the scenario when LLVMContext is populated SymbolicFile will contain a + // reference to it, thus SymbolicFile should be destroyed first. + LLVMContext Context; + SymMap.UseECMap = IsEC; Expected<std::vector<MemberData>> DataOrErr = computeMemberData( StringTable, SymNames, Kind, Thin, Deterministic, WriteSymtab, - isCOFFArchive(Kind) ? &SymMap : nullptr, NewMembers); + isCOFFArchive(Kind) ? &SymMap : nullptr, Context, NewMembers); if (Error E = DataOrErr.takeError()) return E; std::vector<MemberData> &Data = *DataOrErr; @@ -897,9 +997,11 @@ static Error writeArchiveToStream(raw_ostream &Out, uint64_t LastMemberHeaderOffset = 0; uint64_t NumSyms = 0; uint64_t NumSyms32 = 0; // Store symbol number of 32-bit member files. + bool ShouldWriteSymtab = WriteSymtab != SymtabWritingMode::NoSymtab; 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(); @@ -910,21 +1012,17 @@ static Error writeArchiveToStream(raw_ostream &Out, // symbols; the second global symbol table does the same for 64-bit file // members. As a big archive can have both 32-bit and 64-bit file members, // we need to know the number of symbols in each symbol table individually. - if (isAIXBigArchive(Kind) && WriteSymtab) { - Expected<bool> Is64BitOrErr = is64BitSymbolicFile(M.Data); - if (Error E = Is64BitOrErr.takeError()) - return E; - - if (!*Is64BitOrErr) - NumSyms32 += M.Symbols.size(); - } + if (isAIXBigArchive(Kind) && ShouldWriteSymtab) { + if (!is64BitSymbolicFile(M.SymFile.get())) + NumSyms32 += M.Symbols.size(); + } } std::optional<uint64_t> HeadersSize; // The symbol table is put at the end of the big archive file. The symbol // table is at the start of the archive file for other archive formats. - if (WriteSymtab && !is64BitKind(Kind)) { + if (ShouldWriteSymtab && !is64BitKind(Kind)) { // We assume 32-bit offsets to see if 32-bit symbols are possible or not. HeadersSize = computeHeadersSize(Kind, Data.size(), StringTableSize, NumSyms, SymNamesBuf.size(), @@ -962,7 +1060,7 @@ static Error writeArchiveToStream(raw_ostream &Out, Out << "!<arch>\n"; if (!isAIXBigArchive(Kind)) { - if (WriteSymtab) { + if (ShouldWriteSymtab) { if (!HeadersSize) HeadersSize = computeHeadersSize( Kind, Data.size(), StringTableSize, NumSyms, SymNamesBuf.size(), @@ -978,7 +1076,7 @@ static Error writeArchiveToStream(raw_ostream &Out, Out << StringTableMember.Header << StringTableMember.Data << StringTableMember.Padding; - if (WriteSymtab && SymMap.ECMap.size()) + if (ShouldWriteSymtab && SymMap.ECMap.size()) writeECSymbols(Out, Kind, Deterministic, Data, SymMap); for (const MemberData &M : Data) @@ -998,13 +1096,14 @@ static Error writeArchiveToStream(raw_ostream &Out, 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. @@ -1017,18 +1116,13 @@ static Error writeArchiveToStream(raw_ostream &Out, raw_svector_ostream SymNames32(SymNamesBuf32); raw_svector_ostream SymNames64(SymNamesBuf64); - if (WriteSymtab && NumSyms) + if (ShouldWriteSymtab && NumSyms) // Generate the symbol names for the members. - for (const NewArchiveMember &M : NewMembers) { - MemoryBufferRef Buf = M.Buf->getMemBufferRef(); - Expected<bool> Is64BitOrErr = is64BitSymbolicFile(Buf.getBuffer()); - if (!Is64BitOrErr) - return Is64BitOrErr.takeError(); - - bool HasObject; - Expected<std::vector<unsigned>> SymbolsOrErr = - getSymbols(Buf, 0, *Is64BitOrErr ? SymNames64 : SymNames32, nullptr, - HasObject); + for (const auto &M : Data) { + Expected<std::vector<unsigned>> SymbolsOrErr = getSymbols( + M.SymFile.get(), 0, + is64BitSymbolicFile(M.SymFile.get()) ? SymNames64 : SymNames32, + nullptr); if (!SymbolsOrErr) return SymbolsOrErr.takeError(); } @@ -1041,11 +1135,15 @@ static Error writeArchiveToStream(raw_ostream &Out, // the offset to the 32-bit global symbol table, and the 'GlobSym64Offset' // contains the offset to the 64-bit global symbol table. uint64_t GlobalSymbolOffset = - (WriteSymtab && NumSyms32 > 0) ? MemberTableEndOffset : 0; + (ShouldWriteSymtab && + (WriteSymtab != SymtabWritingMode::BigArchive64) && NumSyms32 > 0) + ? MemberTableEndOffset + : 0; uint64_t GlobalSymbolOffset64 = 0; uint64_t NumSyms64 = NumSyms - NumSyms32; - if (WriteSymtab && NumSyms64 > 0) { + if (ShouldWriteSymtab && (WriteSymtab != SymtabWritingMode::BigArchive32) && + NumSyms64 > 0) { if (GlobalSymbolOffset == 0) GlobalSymbolOffset64 = MemberTableEndOffset; else @@ -1063,9 +1161,12 @@ static Error writeArchiveToStream(raw_ostream &Out, // symbol table. printWithSpacePadding(Out, GlobalSymbolOffset, 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( @@ -1073,6 +1174,7 @@ static Error writeArchiveToStream(raw_ostream &Out, 20); // Offset to first member of free list - Not supported yet for (const MemberData &M : Data) { + Out << std::string(M.PreHeadPadSize, '\0'); Out << M.Header << M.Data; if (M.Data.size() % 2) Out << '\0'; @@ -1095,7 +1197,7 @@ static Error writeArchiveToStream(raw_ostream &Out, Out << '\0'; // Name table must be tail padded to an even number of // bytes. - if (WriteSymtab) { + if (ShouldWriteSymtab) { // Write global symbol table for 32-bit file members. if (GlobalSymbolOffset) { writeSymbolTable(Out, Kind, Deterministic, Data, SymNamesBuf32, @@ -1121,7 +1223,7 @@ static Error writeArchiveToStream(raw_ostream &Out, } Error writeArchive(StringRef ArcName, ArrayRef<NewArchiveMember> NewMembers, - bool WriteSymtab, object::Archive::Kind Kind, + SymtabWritingMode WriteSymtab, object::Archive::Kind Kind, bool Deterministic, bool Thin, std::unique_ptr<MemoryBuffer> OldArchiveBuf, bool IsEC) { Expected<sys::fs::TempFile> Temp = @@ -1153,9 +1255,9 @@ Error writeArchive(StringRef ArcName, ArrayRef<NewArchiveMember> NewMembers, } Expected<std::unique_ptr<MemoryBuffer>> -writeArchiveToBuffer(ArrayRef<NewArchiveMember> NewMembers, bool WriteSymtab, - object::Archive::Kind Kind, bool Deterministic, - bool Thin) { +writeArchiveToBuffer(ArrayRef<NewArchiveMember> NewMembers, + SymtabWritingMode WriteSymtab, object::Archive::Kind Kind, + bool Deterministic, bool Thin) { SmallVector<char, 0> ArchiveBufferVector; raw_svector_ostream ArchiveStream(ArchiveBufferVector); |