diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-12-20 14:16:56 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-12-20 14:16:56 +0000 |
commit | 2cab237b5dbfe1b3e9c7aa7a3c02d2b98fcf7462 (patch) | |
tree | 524fe828571f81358bba62fdb6d04c6e5e96a2a4 /contrib/llvm/lib/Object/ArchiveWriter.cpp | |
parent | 6c7828a2807ea5e50c79ca42dbedf2b589ce63b2 (diff) | |
parent | 044eb2f6afba375a914ac9d8024f8f5142bb912e (diff) |
Notes
Diffstat (limited to 'contrib/llvm/lib/Object/ArchiveWriter.cpp')
-rw-r--r-- | contrib/llvm/lib/Object/ArchiveWriter.cpp | 479 |
1 files changed, 271 insertions, 208 deletions
diff --git a/contrib/llvm/lib/Object/ArchiveWriter.cpp b/contrib/llvm/lib/Object/ArchiveWriter.cpp index b052c76d1fed..b3b812daae2e 100644 --- a/contrib/llvm/lib/Object/ArchiveWriter.cpp +++ b/contrib/llvm/lib/Object/ArchiveWriter.cpp @@ -35,6 +35,15 @@ using namespace llvm; +// The SYM64 format is used when an archive's member offsets are larger than +// 32-bits can hold. The need for this shift in format is detected by +// writeArchive. To test this we need to generate a file with a member that has +// an offset larger than 32-bits but this demands a very slow test. To speed +// the test up we use this flag to pretend like the cutoff happens before +// 32-bits and instead happens at some much smaller value. +static cl::opt<int> Sym64Threshold("sym64-threshold", cl::Hidden, + cl::init(32)); + NewArchiveMember::NewArchiveMember(MemoryBufferRef BufRef) : Buf(MemoryBuffer::getMemBuffer(BufRef, false)), MemberName(BufRef.getBufferIdentifier()) {} @@ -111,29 +120,22 @@ Expected<NewArchiveMember> NewArchiveMember::getFile(StringRef FileName, } template <typename T> -static void printWithSpacePadding(raw_fd_ostream &OS, T Data, unsigned Size, - bool MayTruncate = false) { +static void printWithSpacePadding(raw_ostream &OS, T Data, unsigned Size) { uint64_t OldPos = OS.tell(); OS << Data; unsigned SizeSoFar = OS.tell() - OldPos; - if (Size > SizeSoFar) { - OS.indent(Size - SizeSoFar); - } else if (Size < SizeSoFar) { - assert(MayTruncate && "Data doesn't fit in Size"); - // Some of the data this is used for (like UID) can be larger than the - // space available in the archive format. Truncate in that case. - OS.seek(OldPos + Size); - } + assert(SizeSoFar <= Size && "Data doesn't fit in Size"); + OS.indent(Size - SizeSoFar); } static bool isBSDLike(object::Archive::Kind Kind) { switch (Kind) { case object::Archive::K_GNU: + case object::Archive::K_GNU64: return false; case object::Archive::K_BSD: case object::Archive::K_DARWIN: return true; - case object::Archive::K_MIPS64: case object::Archive::K_DARWIN64: case object::Archive::K_COFF: break; @@ -141,8 +143,8 @@ static bool isBSDLike(object::Archive::Kind Kind) { llvm_unreachable("not supported for writting"); } -static void print32(raw_ostream &Out, object::Archive::Kind Kind, - uint32_t Val) { +template <class T> +static void print(raw_ostream &Out, object::Archive::Kind Kind, T Val) { if (isBSDLike(Kind)) support::endian::Writer<support::little>(Out).write(Val); else @@ -150,18 +152,22 @@ static void print32(raw_ostream &Out, object::Archive::Kind Kind, } static void printRestOfMemberHeader( - raw_fd_ostream &Out, const sys::TimePoint<std::chrono::seconds> &ModTime, + raw_ostream &Out, const sys::TimePoint<std::chrono::seconds> &ModTime, unsigned UID, unsigned GID, unsigned Perms, unsigned Size) { printWithSpacePadding(Out, sys::toTimeT(ModTime), 12); - printWithSpacePadding(Out, UID, 6, true); - printWithSpacePadding(Out, GID, 6, true); + + // The format has only 6 chars for uid and gid. Truncate if the provided + // values don't fit. + printWithSpacePadding(Out, UID % 1000000, 6); + printWithSpacePadding(Out, GID % 1000000, 6); + printWithSpacePadding(Out, format("%o", Perms), 8); printWithSpacePadding(Out, Size, 10); Out << "`\n"; } static void -printGNUSmallMemberHeader(raw_fd_ostream &Out, StringRef Name, +printGNUSmallMemberHeader(raw_ostream &Out, StringRef Name, const sys::TimePoint<std::chrono::seconds> &ModTime, unsigned UID, unsigned GID, unsigned Perms, unsigned Size) { @@ -170,11 +176,11 @@ printGNUSmallMemberHeader(raw_fd_ostream &Out, StringRef Name, } static void -printBSDMemberHeader(raw_fd_ostream &Out, StringRef Name, +printBSDMemberHeader(raw_ostream &Out, uint64_t Pos, StringRef Name, const sys::TimePoint<std::chrono::seconds> &ModTime, unsigned UID, unsigned GID, unsigned Perms, unsigned Size) { - uint64_t PosAfterHeader = Out.tell() + 60 + Name.size(); + uint64_t PosAfterHeader = Pos + 60 + Name.size(); // Pad so that even 64 bit object files are aligned. unsigned Pad = OffsetToAlignment(PosAfterHeader, 8); unsigned NameWithPadding = Name.size() + Pad; @@ -182,7 +188,6 @@ printBSDMemberHeader(raw_fd_ostream &Out, StringRef Name, printRestOfMemberHeader(Out, ModTime, UID, GID, Perms, NameWithPadding + Size); Out << Name; - assert(PosAfterHeader == Out.tell()); while (Pad--) Out.write(uint8_t(0)); } @@ -191,21 +196,6 @@ static bool useStringTable(bool Thin, StringRef Name) { return Thin || Name.size() >= 16 || Name.contains('/'); } -static void -printMemberHeader(raw_fd_ostream &Out, object::Archive::Kind Kind, bool Thin, - StringRef Name, - std::vector<unsigned>::iterator &StringMapIndexIter, - const sys::TimePoint<std::chrono::seconds> &ModTime, - unsigned UID, unsigned GID, unsigned Perms, unsigned Size) { - if (isBSDLike(Kind)) - return printBSDMemberHeader(Out, Name, ModTime, UID, GID, Perms, Size); - if (!useStringTable(Thin, Name)) - return printGNUSmallMemberHeader(Out, Name, ModTime, UID, GID, Perms, Size); - Out << '/'; - printWithSpacePadding(Out, *StringMapIndexIter++, 15); - printRestOfMemberHeader(Out, ModTime, UID, GID, Perms, Size); -} - // Compute the relative path from From to To. static std::string computeRelativePath(StringRef From, StringRef To) { if (sys::path::is_absolute(From) || sys::path::is_absolute(To)) @@ -235,41 +225,70 @@ static std::string computeRelativePath(StringRef From, StringRef To) { return Relative.str(); } -static void writeStringTable(raw_fd_ostream &Out, StringRef ArcName, - ArrayRef<NewArchiveMember> Members, - std::vector<unsigned> &StringMapIndexes, - bool Thin) { - unsigned StartOffset = 0; - for (const NewArchiveMember &M : Members) { - StringRef Path = M.Buf->getBufferIdentifier(); - StringRef Name = M.MemberName; - if (!useStringTable(Thin, Name)) - continue; - if (StartOffset == 0) { - printWithSpacePadding(Out, "//", 58); - Out << "`\n"; - StartOffset = Out.tell(); - } - StringMapIndexes.push_back(Out.tell() - StartOffset); +static bool is64BitKind(object::Archive::Kind Kind) { + switch (Kind) { + case object::Archive::K_GNU: + case object::Archive::K_BSD: + case object::Archive::K_DARWIN: + case object::Archive::K_COFF: + return false; + case object::Archive::K_DARWIN64: + case object::Archive::K_GNU64: + return true; + } + llvm_unreachable("not supported for writting"); +} - if (Thin) { - if (M.IsNew) - Out << computeRelativePath(ArcName, Path); - else - Out << M.Buf->getBufferIdentifier(); - } else - Out << Name; +static void addToStringTable(raw_ostream &Out, StringRef ArcName, + const NewArchiveMember &M, bool Thin) { + StringRef ID = M.Buf->getBufferIdentifier(); + if (Thin) { + if (M.IsNew) + Out << computeRelativePath(ArcName, ID); + else + Out << ID; + } else + Out << M.MemberName; + Out << "/\n"; +} - Out << "/\n"; - } - if (StartOffset == 0) - return; - if (Out.tell() % 2) - Out << '\n'; - int Pos = Out.tell(); - Out.seek(StartOffset - 12); - printWithSpacePadding(Out, Pos - StartOffset, 10); - Out.seek(Pos); +static void printMemberHeader(raw_ostream &Out, uint64_t Pos, + raw_ostream &StringTable, + object::Archive::Kind Kind, bool Thin, + StringRef ArcName, const NewArchiveMember &M, + unsigned Size) { + if (isBSDLike(Kind)) + return printBSDMemberHeader(Out, Pos, M.MemberName, M.ModTime, M.UID, M.GID, + M.Perms, Size); + if (!useStringTable(Thin, M.MemberName)) + return printGNUSmallMemberHeader(Out, M.MemberName, M.ModTime, M.UID, M.GID, + M.Perms, Size); + Out << '/'; + uint64_t NamePos = StringTable.tell(); + addToStringTable(StringTable, ArcName, M, Thin); + printWithSpacePadding(Out, NamePos, 15); + printRestOfMemberHeader(Out, M.ModTime, M.UID, M.GID, M.Perms, Size); +} + +namespace { +struct MemberData { + std::vector<unsigned> Symbols; + std::string Header; + StringRef Data; + StringRef Padding; +}; +} // namespace + +static MemberData computeStringTable(StringRef Names) { + unsigned Size = Names.size(); + unsigned Pad = OffsetToAlignment(Size, 2); + std::string Header; + raw_string_ostream Out(Header); + printWithSpacePadding(Out, "//", 48); + printWithSpacePadding(Out, Size + Pad, 10); + Out << "`\n"; + Out.flush(); + return {{}, std::move(Header), Names, Pad ? "\n" : ""}; } static sys::TimePoint<std::chrono::seconds> now(bool Deterministic) { @@ -280,177 +299,222 @@ static sys::TimePoint<std::chrono::seconds> now(bool Deterministic) { return sys::TimePoint<seconds>(); } -// Returns the offset of the first reference to a member offset. -static ErrorOr<unsigned> -writeSymbolTable(raw_fd_ostream &Out, object::Archive::Kind Kind, - ArrayRef<NewArchiveMember> Members, - std::vector<unsigned> &MemberOffsetRefs, bool Deterministic) { - unsigned HeaderStartOffset = 0; - unsigned BodyStartOffset = 0; - SmallString<128> NameBuf; - raw_svector_ostream NameOS(NameBuf); - LLVMContext Context; - for (unsigned MemberNum = 0, N = Members.size(); MemberNum < N; ++MemberNum) { - MemoryBufferRef MemberBuffer = Members[MemberNum].Buf->getMemBufferRef(); - Expected<std::unique_ptr<object::SymbolicFile>> ObjOrErr = - object::SymbolicFile::createSymbolicFile( - MemberBuffer, llvm::file_magic::unknown, &Context); - if (!ObjOrErr) { - // FIXME: check only for "not an object file" errors. - consumeError(ObjOrErr.takeError()); - continue; - } - object::SymbolicFile &Obj = *ObjOrErr.get(); +static bool isArchiveSymbol(const object::BasicSymbolRef &S) { + uint32_t Symflags = S.getFlags(); + if (Symflags & object::SymbolRef::SF_FormatSpecific) + return false; + if (!(Symflags & object::SymbolRef::SF_Global)) + return false; + if (Symflags & object::SymbolRef::SF_Undefined && + !(Symflags & object::SymbolRef::SF_Indirect)) + return false; + return true; +} - if (!HeaderStartOffset) { - HeaderStartOffset = Out.tell(); - if (isBSDLike(Kind)) - printBSDMemberHeader(Out, "__.SYMDEF", now(Deterministic), 0, 0, 0, 0); - else - printGNUSmallMemberHeader(Out, "", now(Deterministic), 0, 0, 0, 0); - BodyStartOffset = Out.tell(); - print32(Out, Kind, 0); // number of entries or bytes - } +static void printNBits(raw_ostream &Out, object::Archive::Kind Kind, + uint64_t Val) { + if (is64BitKind(Kind)) + print<uint64_t>(Out, Kind, Val); + else + print<uint32_t>(Out, Kind, Val); +} - for (const object::BasicSymbolRef &S : Obj.symbols()) { - uint32_t Symflags = S.getFlags(); - if (Symflags & object::SymbolRef::SF_FormatSpecific) - continue; - if (!(Symflags & object::SymbolRef::SF_Global)) - continue; - if (Symflags & object::SymbolRef::SF_Undefined && - !(Symflags & object::SymbolRef::SF_Indirect)) - continue; - - unsigned NameOffset = NameOS.tell(); - if (auto EC = S.printName(NameOS)) - return EC; - NameOS << '\0'; - MemberOffsetRefs.push_back(MemberNum); - if (isBSDLike(Kind)) - print32(Out, Kind, NameOffset); - print32(Out, Kind, 0); // member offset - } - } +static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind, + bool Deterministic, ArrayRef<MemberData> Members, + StringRef StringTable) { + if (StringTable.empty()) + return; - if (HeaderStartOffset == 0) - return 0; + unsigned NumSyms = 0; + for (const MemberData &M : Members) + NumSyms += M.Symbols.size(); - // ld64 prefers the cctools type archive which pads its string table to a - // boundary of sizeof(int32_t). + unsigned Size = 0; + Size += is64BitKind(Kind) ? 8 : 4; // Number of entries if (isBSDLike(Kind)) - for (unsigned P = OffsetToAlignment(NameOS.tell(), sizeof(int32_t)); P--;) - NameOS << '\0'; - - StringRef StringTable = NameOS.str(); + Size += NumSyms * 8; // Table + else if (is64BitKind(Kind)) + Size += NumSyms * 8; // Table + else + Size += NumSyms * 4; // Table if (isBSDLike(Kind)) - print32(Out, Kind, StringTable.size()); // byte count of the string table - Out << StringTable; - // 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 (StringTable.size() == 0) - print32(Out, Kind, 0); + Size += 4; // byte count + Size += StringTable.size(); + // ld64 expects the members to be 8-byte aligned for 64-bit content and at + // least 4-byte aligned for 32-bit content. Opt for the larger encoding + // uniformly. + // We do this for all bsd formats because it simplifies aligning members. + unsigned Alignment = isBSDLike(Kind) ? 8 : 2; + unsigned Pad = OffsetToAlignment(Size, Alignment); + Size += Pad; - // ld64 requires the next member header to start at an offset that is - // 4 bytes aligned. - unsigned Pad = OffsetToAlignment(Out.tell(), 4); - while (Pad--) - Out.write(uint8_t(0)); + if (isBSDLike(Kind)) + printBSDMemberHeader(Out, Out.tell(), "__.SYMDEF", now(Deterministic), 0, 0, + 0, Size); + else if (is64BitKind(Kind)) + printGNUSmallMemberHeader(Out, "/SYM64", now(Deterministic), 0, 0, 0, Size); + else + printGNUSmallMemberHeader(Out, "", now(Deterministic), 0, 0, 0, Size); - // Patch up the size of the symbol table now that we know how big it is. - unsigned Pos = Out.tell(); - const unsigned MemberHeaderSize = 60; - Out.seek(HeaderStartOffset + 48); // offset of the size field. - printWithSpacePadding(Out, Pos - MemberHeaderSize - HeaderStartOffset, 10); + uint64_t Pos = Out.tell() + Size; - // Patch up the number of symbols. - Out.seek(BodyStartOffset); - unsigned NumSyms = MemberOffsetRefs.size(); if (isBSDLike(Kind)) - print32(Out, Kind, NumSyms * 8); + print<uint32_t>(Out, Kind, NumSyms * 8); else - print32(Out, Kind, NumSyms); + printNBits(Out, Kind, NumSyms); + + for (const MemberData &M : Members) { + for (unsigned StringOffset : M.Symbols) { + if (isBSDLike(Kind)) + print<uint32_t>(Out, Kind, StringOffset); + printNBits(Out, Kind, Pos); // member offset + } + Pos += M.Header.size() + M.Data.size() + M.Padding.size(); + } + + if (isBSDLike(Kind)) + // byte count of the string table + print<uint32_t>(Out, Kind, StringTable.size()); + Out << StringTable; - Out.seek(Pos); - return BodyStartOffset + 4; + while (Pad--) + Out.write(uint8_t(0)); } -std::pair<StringRef, std::error_code> -llvm::writeArchive(StringRef ArcName, - std::vector<NewArchiveMember> &NewMembers, - bool WriteSymtab, object::Archive::Kind Kind, - bool Deterministic, bool Thin, - std::unique_ptr<MemoryBuffer> OldArchiveBuf) { - assert((!Thin || !isBSDLike(Kind)) && "Only the gnu format has a thin mode"); - SmallString<128> TmpArchive; - int TmpArchiveFD; - if (auto EC = sys::fs::createUniqueFile(ArcName + ".temp-archive-%%%%%%%.a", - TmpArchiveFD, TmpArchive)) - return std::make_pair(ArcName, EC); - - tool_output_file Output(TmpArchive, TmpArchiveFD); - raw_fd_ostream &Out = Output.os(); - if (Thin) - Out << "!<thin>\n"; - else - Out << "!<arch>\n"; +static Expected<std::vector<unsigned>> +getSymbols(MemoryBufferRef Buf, raw_ostream &SymNames, bool &HasObject) { + std::vector<unsigned> Ret; + LLVMContext Context; - std::vector<unsigned> MemberOffsetRefs; + Expected<std::unique_ptr<object::SymbolicFile>> ObjOrErr = + object::SymbolicFile::createSymbolicFile(Buf, llvm::file_magic::unknown, + &Context); + if (!ObjOrErr) { + // FIXME: check only for "not an object file" errors. + consumeError(ObjOrErr.takeError()); + return Ret; + } - unsigned MemberReferenceOffset = 0; - if (WriteSymtab) { - ErrorOr<unsigned> MemberReferenceOffsetOrErr = writeSymbolTable( - Out, Kind, NewMembers, MemberOffsetRefs, Deterministic); - if (auto EC = MemberReferenceOffsetOrErr.getError()) - return std::make_pair(ArcName, EC); - MemberReferenceOffset = MemberReferenceOffsetOrErr.get(); + HasObject = true; + object::SymbolicFile &Obj = *ObjOrErr.get(); + for (const object::BasicSymbolRef &S : Obj.symbols()) { + if (!isArchiveSymbol(S)) + continue; + Ret.push_back(SymNames.tell()); + if (auto EC = S.printName(SymNames)) + return errorCodeToError(EC); + SymNames << '\0'; } + return Ret; +} + +static Expected<std::vector<MemberData>> +computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames, + object::Archive::Kind Kind, bool Thin, StringRef ArcName, + ArrayRef<NewArchiveMember> NewMembers) { + static char PaddingData[8] = {'\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n'}; - std::vector<unsigned> StringMapIndexes; - if (!isBSDLike(Kind)) - writeStringTable(Out, ArcName, NewMembers, StringMapIndexes, Thin); + // This ignores the symbol table, but we only need the value mod 8 and the + // symbol table is aligned to be a multiple of 8 bytes + uint64_t Pos = 0; - std::vector<unsigned>::iterator StringMapIndexIter = StringMapIndexes.begin(); - std::vector<unsigned> MemberOffset; + std::vector<MemberData> Ret; + bool HasObject = false; for (const NewArchiveMember &M : NewMembers) { - MemoryBufferRef File = M.Buf->getMemBufferRef(); - unsigned Padding = 0; + std::string Header; + raw_string_ostream Out(Header); - unsigned Pos = Out.tell(); - MemberOffset.push_back(Pos); + 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 // least 4-byte aligned for 32-bit content. Opt for the larger encoding // uniformly. This matches the behaviour with cctools and ensures that ld64 // is happy with archives that we generate. - if (Kind == object::Archive::K_DARWIN) - Padding = OffsetToAlignment(M.Buf->getBufferSize(), 8); + unsigned MemberPadding = Kind == object::Archive::K_DARWIN + ? OffsetToAlignment(Data.size(), 8) + : 0; + unsigned TailPadding = OffsetToAlignment(Data.size() + MemberPadding, 2); + StringRef Padding = StringRef(PaddingData, MemberPadding + TailPadding); + + printMemberHeader(Out, Pos, StringTable, Kind, Thin, ArcName, M, + Buf.getBufferSize() + MemberPadding); + Out.flush(); + + Expected<std::vector<unsigned>> Symbols = + getSymbols(Buf, SymNames, HasObject); + if (auto E = Symbols.takeError()) + return std::move(E); + + Pos += Header.size() + Data.size() + Padding.size(); + Ret.push_back({std::move(*Symbols), std::move(Header), Data, Padding}); + } + // 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) + SymNames << '\0' << '\0' << '\0'; + return Ret; +} - printMemberHeader(Out, Kind, Thin, M.MemberName, StringMapIndexIter, - M.ModTime, M.UID, M.GID, M.Perms, - M.Buf->getBufferSize() + Padding); +Error llvm::writeArchive(StringRef ArcName, + ArrayRef<NewArchiveMember> NewMembers, + bool WriteSymtab, object::Archive::Kind Kind, + bool Deterministic, bool Thin, + std::unique_ptr<MemoryBuffer> OldArchiveBuf) { + assert((!Thin || !isBSDLike(Kind)) && "Only the gnu format has a thin mode"); - if (!Thin) - Out << File.getBuffer(); + SmallString<0> SymNamesBuf; + raw_svector_ostream SymNames(SymNamesBuf); + SmallString<0> StringTableBuf; + raw_svector_ostream StringTable(StringTableBuf); - while (Padding--) - Out << '\n'; - if (Out.tell() % 2) - Out << '\n'; - } + Expected<std::vector<MemberData>> DataOrErr = + computeMemberData(StringTable, SymNames, Kind, Thin, ArcName, NewMembers); + if (Error E = DataOrErr.takeError()) + return E; + std::vector<MemberData> &Data = *DataOrErr; - if (MemberReferenceOffset) { - Out.seek(MemberReferenceOffset); - for (unsigned MemberNum : MemberOffsetRefs) { - if (isBSDLike(Kind)) - Out.seek(Out.tell() + 4); // skip over the string offset - print32(Out, Kind, MemberOffset[MemberNum]); + if (!StringTableBuf.empty()) + Data.insert(Data.begin(), computeStringTable(StringTableBuf)); + + // We would like to detect if we need to switch to a 64-bit symbol table. + if (WriteSymtab) { + uint64_t MaxOffset = 0; + uint64_t LastOffset = MaxOffset; + for (const auto& M : Data) { + // Record the start of the member's offset + LastOffset = MaxOffset; + // Account for the size of each part associated with the member. + MaxOffset += M.Header.size() + M.Data.size() + M.Padding.size(); + // We assume 32-bit symbols to see if 32-bit symbols are possible or not. + MaxOffset += M.Symbols.size() * 4; } + // If LastOffset isn't going to fit in a 32-bit varible we need to switch + // to 64-bit. Note that the file can be larger than 4GB as long as the last + // member starts before the 4GB offset. + if (LastOffset >= (1ULL << Sym64Threshold)) + Kind = object::Archive::K_GNU64; } - Output.keep(); - Out.close(); + Expected<sys::fs::TempFile> Temp = + sys::fs::TempFile::create(ArcName + ".temp-archive-%%%%%%%.a"); + if (!Temp) + return Temp.takeError(); + + raw_fd_ostream Out(Temp->FD, false); + if (Thin) + Out << "!<thin>\n"; + else + Out << "!<arch>\n"; + + if (WriteSymtab) + writeSymbolTable(Out, Kind, Deterministic, Data, SymNamesBuf); + + for (const MemberData &M : Data) + Out << M.Header << M.Data << M.Padding; + + Out.flush(); // At this point, we no longer need whatever backing memory // was used to generate the NewMembers. On Windows, this buffer @@ -464,6 +528,5 @@ llvm::writeArchive(StringRef ArcName, // closed before we attempt to rename. OldArchiveBuf.reset(); - sys::fs::rename(TmpArchive, ArcName); - return std::make_pair("", std::error_code()); + return Temp->keep(ArcName); } |