mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 12:12:47 +01:00
llvm-ar: Darwin archive format fixes.
* Support writing the DARWIN64 symbol table format. * In darwin archives, emit a symbol table whenever requested, even when there are no members, as the apple linker will abort if given an archive without a symbol table. Added tests for same, and also simplified and moved the GNU 64-bit symbol table test into archive-symtab.test. llvm-svn: 344183
This commit is contained in:
parent
41a99d48b6
commit
6f1053539e
@ -121,6 +121,11 @@ static void printWithSpacePadding(raw_ostream &OS, T Data, unsigned Size) {
|
||||
OS.indent(Size - SizeSoFar);
|
||||
}
|
||||
|
||||
static bool isDarwin(object::Archive::Kind Kind) {
|
||||
return Kind == object::Archive::K_DARWIN ||
|
||||
Kind == object::Archive::K_DARWIN64;
|
||||
}
|
||||
|
||||
static bool isBSDLike(object::Archive::Kind Kind) {
|
||||
switch (Kind) {
|
||||
case object::Archive::K_GNU:
|
||||
@ -128,8 +133,8 @@ static bool isBSDLike(object::Archive::Kind Kind) {
|
||||
return false;
|
||||
case object::Archive::K_BSD:
|
||||
case object::Archive::K_DARWIN:
|
||||
return true;
|
||||
case object::Archive::K_DARWIN64:
|
||||
return true;
|
||||
case object::Archive::K_COFF:
|
||||
break;
|
||||
}
|
||||
@ -314,7 +319,9 @@ static void printNBits(raw_ostream &Out, object::Archive::Kind Kind,
|
||||
static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind,
|
||||
bool Deterministic, ArrayRef<MemberData> Members,
|
||||
StringRef StringTable) {
|
||||
if (StringTable.empty())
|
||||
// We don't write a symbol table on an archive with no members -- except on
|
||||
// Darwin, where the linker will abort unless the archive has a symbol table.
|
||||
if (StringTable.empty() && !isDarwin(Kind))
|
||||
return;
|
||||
|
||||
unsigned NumSyms = 0;
|
||||
@ -322,15 +329,15 @@ static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind,
|
||||
NumSyms += M.Symbols.size();
|
||||
|
||||
unsigned Size = 0;
|
||||
Size += is64BitKind(Kind) ? 8 : 4; // Number of entries
|
||||
unsigned OffsetSize = is64BitKind(Kind) ? sizeof(uint64_t) : sizeof(uint32_t);
|
||||
|
||||
Size += OffsetSize; // Number of entries
|
||||
if (isBSDLike(Kind))
|
||||
Size += NumSyms * 8; // Table
|
||||
else if (is64BitKind(Kind))
|
||||
Size += NumSyms * 8; // Table
|
||||
Size += NumSyms * OffsetSize * 2; // Table
|
||||
else
|
||||
Size += NumSyms * 4; // Table
|
||||
Size += NumSyms * OffsetSize; // Table
|
||||
if (isBSDLike(Kind))
|
||||
Size += 4; // byte count
|
||||
Size += OffsetSize; // 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
|
||||
@ -340,25 +347,26 @@ static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind,
|
||||
unsigned Pad = OffsetToAlignment(Size, Alignment);
|
||||
Size += Pad;
|
||||
|
||||
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);
|
||||
if (isBSDLike(Kind)) {
|
||||
const char *Name = is64BitKind(Kind) ? "__.SYMDEF_64" : "__.SYMDEF";
|
||||
printBSDMemberHeader(Out, Out.tell(), Name, now(Deterministic), 0, 0, 0,
|
||||
Size);
|
||||
} else {
|
||||
const char *Name = is64BitKind(Kind) ? "/SYM64" : "";
|
||||
printGNUSmallMemberHeader(Out, Name, now(Deterministic), 0, 0, 0, Size);
|
||||
}
|
||||
|
||||
uint64_t Pos = Out.tell() + Size;
|
||||
|
||||
if (isBSDLike(Kind))
|
||||
print<uint32_t>(Out, Kind, NumSyms * 8);
|
||||
printNBits(Out, Kind, NumSyms * 2 * OffsetSize);
|
||||
else
|
||||
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, StringOffset);
|
||||
printNBits(Out, Kind, Pos); // member offset
|
||||
}
|
||||
Pos += M.Header.size() + M.Data.size() + M.Padding.size();
|
||||
@ -366,7 +374,7 @@ static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind,
|
||||
|
||||
if (isBSDLike(Kind))
|
||||
// byte count of the string table
|
||||
print<uint32_t>(Out, Kind, StringTable.size());
|
||||
printNBits(Out, Kind, StringTable.size());
|
||||
Out << StringTable;
|
||||
|
||||
while (Pad--)
|
||||
@ -466,9 +474,7 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
|
||||
// See also the functions that handle the lookup:
|
||||
// in lldb: ObjectContainerBSDArchive::Archive::FindObject()
|
||||
// in llvm/tools/dsymutil: BinaryHolder::GetArchiveMemberBuffers().
|
||||
bool UniqueTimestamps =
|
||||
Deterministic && (Kind == object::Archive::K_DARWIN ||
|
||||
Kind == object::Archive::K_DARWIN64);
|
||||
bool UniqueTimestamps = Deterministic && isDarwin(Kind);
|
||||
std::map<StringRef, unsigned> FilenameCount;
|
||||
if (UniqueTimestamps) {
|
||||
for (const NewArchiveMember &M : NewMembers)
|
||||
@ -488,9 +494,8 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
|
||||
// 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.
|
||||
unsigned MemberPadding = Kind == object::Archive::K_DARWIN
|
||||
? OffsetToAlignment(Data.size(), 8)
|
||||
: 0;
|
||||
unsigned MemberPadding =
|
||||
isDarwin(Kind) ? OffsetToAlignment(Data.size(), 8) : 0;
|
||||
unsigned TailPadding = OffsetToAlignment(Data.size() + MemberPadding, 2);
|
||||
StringRef Padding = StringRef(PaddingData, MemberPadding + TailPadding);
|
||||
|
||||
@ -569,8 +574,12 @@ Error llvm::writeArchive(StringRef ArcName,
|
||||
// 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;
|
||||
if (LastOffset >= (1ULL << Sym64Threshold)) {
|
||||
if (Kind == object::Archive::K_DARWIN)
|
||||
Kind = object::Archive::K_DARWIN64;
|
||||
else
|
||||
Kind = object::Archive::K_GNU64;
|
||||
}
|
||||
}
|
||||
|
||||
Expected<sys::fs::TempFile> Temp =
|
||||
|
@ -1,40 +0,0 @@
|
||||
# REQUIRES: llvm-64-bits
|
||||
# REQUIRES: system-linux
|
||||
# REQUIRES: shell
|
||||
|
||||
# RUN: yaml2obj %s > %t
|
||||
# RUN: dd if=%t of=%t bs=1 count=0 seek=1M
|
||||
# RUN: rm -f %t.lib
|
||||
# RUN: cp %t %t2
|
||||
# RUN: SYM64_THRESHOLD=19 llvm-ar cr %t.lib %t %t2 %p/Inputs/trivial-object-test.elf-x86-64
|
||||
# RUN: llvm-nm --print-armap %t.lib | FileCheck %s
|
||||
# RUN: grep SYM64 %t.lib
|
||||
|
||||
# Delete temp files. They are too large.
|
||||
# RUN: rm -f %t %t2 %t.lib
|
||||
|
||||
!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-GNU64-write.test.tmp:
|
||||
|
||||
# CHECK: archive-GNU64-write.test.tmp2:
|
||||
|
||||
# CHECK: trivial-object-test.elf-x86-64:
|
||||
# CHECK-NEXT: U SomeOtherFunction
|
||||
# CHECK-NEXT: 0000000000000000 T main
|
||||
# CHECK-NEXT: U puts
|
@ -38,7 +38,7 @@ BSD-SAME: #1/16 0 0 0 644 20 `
|
||||
BSD-NEXT: 0123456789abcdefzed.
|
||||
|
||||
RUN: rm -f %t.a
|
||||
RUN: llvm-ar --format=darwin rc %t.a 0123456789abcde 0123456789abcdef
|
||||
RUN: llvm-ar --format=darwin rcS %t.a 0123456789abcde 0123456789abcdef
|
||||
RUN: cat %t.a | FileCheck -strict-whitespace --check-prefix=DARWIN %s
|
||||
|
||||
DARWIN: !<arch>
|
||||
|
@ -2,6 +2,11 @@ RUN: rm -f %t.a
|
||||
RUN: llvm-ar rcsU %t.a %p/Inputs/trivial-object-test.elf-x86-64 %p/Inputs/trivial-object-test2.elf-x86-64
|
||||
RUN: llvm-nm -M %t.a | FileCheck %s
|
||||
|
||||
RUN: rm -f %t.a
|
||||
RUN: env SYM64_THRESHOLD=1 llvm-ar rcsU %t.a %p/Inputs/trivial-object-test.elf-x86-64 %p/Inputs/trivial-object-test2.elf-x86-64
|
||||
RUN: llvm-nm -M %t.a | FileCheck %s
|
||||
RUXX: grep SYM64 %t.a
|
||||
|
||||
CHECK: Archive map
|
||||
CHECK-NEXT: main in trivial-object-test.elf-x86-64
|
||||
CHECK-NEXT: foo in trivial-object-test2.elf-x86-64
|
||||
@ -82,6 +87,11 @@ RUN: rm -f %t.a
|
||||
RUN: llvm-ar --format=bsd rcsU %t.a %p/Inputs/trivial-object-test.macho-x86-64 %p/Inputs/trivial-object-test2.macho-x86-64
|
||||
RUN: llvm-nm -M %t.a | FileCheck --check-prefix=MACHO %s
|
||||
|
||||
RUN: rm -f %t.a
|
||||
RUN: env SYM64_THRESHOLD=1 llvm-ar --format=darwin rcsU %t.a %p/Inputs/trivial-object-test.macho-x86-64 %p/Inputs/trivial-object-test2.macho-x86-64
|
||||
RUN: llvm-nm -M %t.a | FileCheck --check-prefix=MACHO %s
|
||||
RUN: grep '__\.SYMDEF_64' %t.a
|
||||
|
||||
MACHO: Archive map
|
||||
MACHO-NEXT: _main in trivial-object-test.macho-x86-64
|
||||
MACHO-NEXT: _foo in trivial-object-test2.macho-x86-64
|
||||
@ -138,3 +148,21 @@ RUN: llvm-ar --format=gnu rcsD %t.a %p/Inputs/trivial-object-test.macho-x86-64
|
||||
RUN: FileCheck --check-prefix=GNU-SYMTAB-ALIGN %s < %t.a
|
||||
GNU-SYMTAB-ALIGN: !<arch>
|
||||
GNU-SYMTAB-ALIGN-NEXT: / 0 0 0 0 14 `
|
||||
|
||||
|
||||
** Test the behavior of an empty archive:
|
||||
|
||||
No symbol table emitted for GNU archives
|
||||
RUN: rm -f %t.a
|
||||
RUN: llvm-ar rcs --format=gnu %t.a
|
||||
RUN: not grep -q '/ ' %t.a
|
||||
|
||||
No symbol table for BSD archives
|
||||
RUN: rm -f %t.a
|
||||
RUN: llvm-ar rcs --format=bsd %t.a
|
||||
RUN: not grep -q '__\.SYMDEF' %t.a
|
||||
|
||||
And we do emit a symbol table for DARWIN archives
|
||||
RUN: rm -f %t.a
|
||||
RUN: llvm-ar rcs --format=darwin %t.a
|
||||
RUN: grep -q '__\.SYMDEF' %t.a
|
||||
|
Loading…
Reference in New Issue
Block a user