1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-02-01 13:11:39 +01:00

Reland "Add support for writing 64-bit symbol tables for archives when offsets become too large for 32-bit"

Tests were failing because some bots were running out of address
space and memory. Additionally the test was very slow. These issues
were solved by changing the test to take advantage of sparse filse and
restricting the test to run only on 64-bit systems.

This should fix https://bugs.llvm.org//show_bug.cgi?id=34189

This change makes it so that if writing a K_GNU style archive, you need
to output a > 32-bit offset it should output in K_GNU64 style instead.

Differential Revision: https://reviews.llvm.org/D36812

llvm-svn: 317352
This commit is contained in:
Jake Ehrlich 2017-11-03 19:15:06 +00:00
parent d171e076c9
commit 61efc7df96
2 changed files with 90 additions and 9 deletions

View File

@ -122,11 +122,11 @@ static void printWithSpacePadding(raw_ostream &OS, T Data, unsigned Size) {
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 +134,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
@ -216,6 +216,20 @@ static std::string computeRelativePath(StringRef From, StringRef To) {
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 +302,14 @@ static bool isArchiveSymbol(const object::BasicSymbolRef &S) {
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 +321,11 @@ static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind,
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 +342,30 @@ static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind,
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,6 +469,25 @@ Error llvm::writeArchive(StringRef ArcName,
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 >> 32 != 0)
Kind = object::Archive::K_GNU64;
}
SmallString<128> TmpArchive;
int TmpArchiveFD;
if (auto EC = sys::fs::createUniqueFile(ArcName + ".temp-archive-%%%%%%%.a",

View File

@ -0,0 +1,35 @@
# REQUIRES: llvm-64-bits
# REQUIRES: system-linux
# RUN: yaml2obj %s > %t
# RUN: dd if=%t of=%t bs=1 count=0 seek=2200M
# RUN: rm -f %t.lib
# RUN: cp %t %t2
# RUN: llvm-ar cr %t.lib %t %t2 %p/Inputs/trivial-object-test.elf-x86-64
# RUN: llvm-nm --print-armap %t.lib | FileCheck %s
!ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_EXEC
Machine: EM_X86_64
Sections:
- Name: .data
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC ]
AddressAlign: 0x0000000000000001
Content: "00"
Size: 32
# CHECK: Archive map
# CHECK-NEXT: main in trivial-object-test.elf-x86-64
# CHECK: archive-SYM64-write.test.tmp:
# CHECK: archive-SYM64-write.test.tmp2:
# CHECK: trivial-object-test.elf-x86-64:
# CHECK-NEXT: U SomeOtherFunction
# CHECK-NEXT: 0000000000000000 T main
# CHECK-NEXT: U puts