Mercurial > hg > CbC > CbC_llvm
diff lib/Object/ArchiveWriter.cpp @ 134:3a76565eade5 LLVM5.0.1
update 5.0.1
author | mir3636 |
---|---|
date | Sat, 17 Feb 2018 09:57:20 +0900 |
parents | 803732b1fca8 |
children | c2174574ed3a |
line wrap: on
line diff
--- a/lib/Object/ArchiveWriter.cpp Fri Feb 16 19:10:49 2018 +0900 +++ b/lib/Object/ArchiveWriter.cpp Sat Feb 17 09:57:20 2018 +0900 @@ -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()) {} @@ -122,11 +131,11 @@ 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_GNU64: case object::Archive::K_DARWIN64: case object::Archive::K_COFF: break; @@ -134,8 +143,8 @@ 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 @@ -216,6 +225,20 @@ return Relative.str(); } +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"); +} + static void addToStringTable(raw_ostream &Out, StringRef ArcName, const NewArchiveMember &M, bool Thin) { StringRef ID = M.Buf->getBufferIdentifier(); @@ -288,6 +311,14 @@ return true; } +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); +} + static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind, bool Deterministic, ArrayRef<MemberData> Members, StringRef StringTable) { @@ -299,9 +330,11 @@ NumSyms += M.Symbols.size(); unsigned Size = 0; - Size += 4; // Number of entries + Size += is64BitKind(Kind) ? 8 : 4; // Number of entries if (isBSDLike(Kind)) Size += NumSyms * 8; // Table + else if (is64BitKind(Kind)) + Size += NumSyms * 8; // Table else Size += NumSyms * 4; // Table if (isBSDLike(Kind)) @@ -318,27 +351,30 @@ 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); uint64_t Pos = Out.tell() + 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)) - print32(Out, Kind, StringOffset); - print32(Out, Kind, Pos); // member offset + 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)) - print32(Out, Kind, StringTable.size()); // byte count of the string table + // byte count of the string table + print<uint32_t>(Out, Kind, StringTable.size()); Out << StringTable; while (Pad--) @@ -442,14 +478,31 @@ if (!StringTableBuf.empty()) Data.insert(Data.begin(), computeStringTable(StringTableBuf)); - SmallString<128> TmpArchive; - int TmpArchiveFD; - if (auto EC = sys::fs::createUniqueFile(ArcName + ".temp-archive-%%%%%%%.a", - TmpArchiveFD, TmpArchive)) - return errorCodeToError(EC); + // 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; + } - ToolOutputFile Output(TmpArchive, TmpArchiveFD); - raw_fd_ostream &Out = Output.os(); + 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 @@ -461,8 +514,7 @@ for (const MemberData &M : Data) Out << M.Header << M.Data << M.Padding; - Output.keep(); - Out.close(); + Out.flush(); // At this point, we no longer need whatever backing memory // was used to generate the NewMembers. On Windows, this buffer @@ -476,6 +528,5 @@ // closed before we attempt to rename. OldArchiveBuf.reset(); - sys::fs::rename(TmpArchive, ArcName); - return Error::success(); + return Temp->keep(ArcName); }