aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm/lib/Object/ArchiveWriter.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-12-20 14:16:56 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-12-20 14:16:56 +0000
commit2cab237b5dbfe1b3e9c7aa7a3c02d2b98fcf7462 (patch)
tree524fe828571f81358bba62fdb6d04c6e5e96a2a4 /contrib/llvm/lib/Object/ArchiveWriter.cpp
parent6c7828a2807ea5e50c79ca42dbedf2b589ce63b2 (diff)
parent044eb2f6afba375a914ac9d8024f8f5142bb912e (diff)
Notes
Diffstat (limited to 'contrib/llvm/lib/Object/ArchiveWriter.cpp')
-rw-r--r--contrib/llvm/lib/Object/ArchiveWriter.cpp479
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);
}