Skip to content
This repository was archived by the owner on Apr 23, 2020. It is now read-only.

Commit b3d6348

Browse files
committed
Add support for writing 64-bit symbol tables for archives when offsets become too large for 32-bit
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 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@316805 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 31407d3 commit b3d6348

File tree

2 files changed

+86
-9
lines changed

2 files changed

+86
-9
lines changed

lib/Object/ArchiveWriter.cpp

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -122,20 +122,20 @@ static void printWithSpacePadding(raw_ostream &OS, T Data, unsigned Size) {
122122
static bool isBSDLike(object::Archive::Kind Kind) {
123123
switch (Kind) {
124124
case object::Archive::K_GNU:
125+
case object::Archive::K_GNU64:
125126
return false;
126127
case object::Archive::K_BSD:
127128
case object::Archive::K_DARWIN:
128129
return true;
129-
case object::Archive::K_GNU64:
130130
case object::Archive::K_DARWIN64:
131131
case object::Archive::K_COFF:
132132
break;
133133
}
134134
llvm_unreachable("not supported for writting");
135135
}
136136

137-
static void print32(raw_ostream &Out, object::Archive::Kind Kind,
138-
uint32_t Val) {
137+
template <class T>
138+
static void print(raw_ostream &Out, object::Archive::Kind Kind, T Val) {
139139
if (isBSDLike(Kind))
140140
support::endian::Writer<support::little>(Out).write(Val);
141141
else
@@ -216,6 +216,20 @@ static std::string computeRelativePath(StringRef From, StringRef To) {
216216
return Relative.str();
217217
}
218218

219+
static bool is64BitKind(object::Archive::Kind Kind) {
220+
switch (Kind) {
221+
case object::Archive::K_GNU:
222+
case object::Archive::K_BSD:
223+
case object::Archive::K_DARWIN:
224+
case object::Archive::K_COFF:
225+
return false;
226+
case object::Archive::K_DARWIN64:
227+
case object::Archive::K_GNU64:
228+
return true;
229+
}
230+
llvm_unreachable("not supported for writting");
231+
}
232+
219233
static void addToStringTable(raw_ostream &Out, StringRef ArcName,
220234
const NewArchiveMember &M, bool Thin) {
221235
StringRef ID = M.Buf->getBufferIdentifier();
@@ -288,6 +302,14 @@ static bool isArchiveSymbol(const object::BasicSymbolRef &S) {
288302
return true;
289303
}
290304

305+
static void printNBits(raw_ostream &Out, object::Archive::Kind Kind,
306+
uint64_t Val) {
307+
if (is64BitKind(Kind))
308+
print<uint64_t>(Out, Kind, Val);
309+
else
310+
print<uint32_t>(Out, Kind, Val);
311+
}
312+
291313
static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind,
292314
bool Deterministic, ArrayRef<MemberData> Members,
293315
StringRef StringTable) {
@@ -299,9 +321,11 @@ static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind,
299321
NumSyms += M.Symbols.size();
300322

301323
unsigned Size = 0;
302-
Size += 4; // Number of entries
324+
Size += is64BitKind(Kind) ? 8 : 4; // Number of entries
303325
if (isBSDLike(Kind))
304326
Size += NumSyms * 8; // Table
327+
else if (is64BitKind(Kind))
328+
Size += NumSyms * 8; // Table
305329
else
306330
Size += NumSyms * 4; // Table
307331
if (isBSDLike(Kind))
@@ -318,27 +342,30 @@ static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind,
318342
if (isBSDLike(Kind))
319343
printBSDMemberHeader(Out, Out.tell(), "__.SYMDEF", now(Deterministic), 0, 0,
320344
0, Size);
345+
else if (is64BitKind(Kind))
346+
printGNUSmallMemberHeader(Out, "/SYM64", now(Deterministic), 0, 0, 0, Size);
321347
else
322348
printGNUSmallMemberHeader(Out, "", now(Deterministic), 0, 0, 0, Size);
323349

324350
uint64_t Pos = Out.tell() + Size;
325351

326352
if (isBSDLike(Kind))
327-
print32(Out, Kind, NumSyms * 8);
353+
print<uint32_t>(Out, Kind, NumSyms * 8);
328354
else
329-
print32(Out, Kind, NumSyms);
355+
printNBits(Out, Kind, NumSyms);
330356

331357
for (const MemberData &M : Members) {
332358
for (unsigned StringOffset : M.Symbols) {
333359
if (isBSDLike(Kind))
334-
print32(Out, Kind, StringOffset);
335-
print32(Out, Kind, Pos); // member offset
360+
print<uint32_t>(Out, Kind, StringOffset);
361+
printNBits(Out, Kind, Pos); // member offset
336362
}
337363
Pos += M.Header.size() + M.Data.size() + M.Padding.size();
338364
}
339365

340366
if (isBSDLike(Kind))
341-
print32(Out, Kind, StringTable.size()); // byte count of the string table
367+
// byte count of the string table
368+
print<uint32_t>(Out, Kind, StringTable.size());
342369
Out << StringTable;
343370

344371
while (Pad--)
@@ -442,6 +469,25 @@ Error llvm::writeArchive(StringRef ArcName,
442469
if (!StringTableBuf.empty())
443470
Data.insert(Data.begin(), computeStringTable(StringTableBuf));
444471

472+
// We would like to detect if we need to switch to a 64-bit symbol table.
473+
if (WriteSymtab) {
474+
uint64_t MaxOffset = 0;
475+
uint64_t LastOffset = MaxOffset;
476+
for (const auto& M : Data) {
477+
// Record the start of the member's offset
478+
LastOffset = MaxOffset;
479+
// Account for the size of each part associated with the member.
480+
MaxOffset += M.Header.size() + M.Data.size() + M.Padding.size();
481+
// We assume 32-bit symbols to see if 32-bit symbols are possible or not.
482+
MaxOffset += M.Symbols.size() * 4;
483+
}
484+
// If LastOffset isn't going to fit in a 32-bit varible we need to switch
485+
// to 64-bit. Note that the file can be larger than 4GB as long as the last
486+
// member starts before the 4GB offset.
487+
if (LastOffset >> 32 != 0)
488+
Kind = object::Archive::K_GNU64;
489+
}
490+
445491
SmallString<128> TmpArchive;
446492
int TmpArchiveFD;
447493
if (auto EC = sys::fs::createUniqueFile(ArcName + ".temp-archive-%%%%%%%.a",

test/Object/archive-SYM64-write.test

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# RUN: yaml2obj %s > %t
2+
# RUN: rm -f %t.lib
3+
# RUN: cp %t %t2
4+
# RUN: llvm-ar cr %t.lib %t %t2 %p/Inputs/trivial-object-test.elf-x86-64
5+
# RUN: llvm-nm --print-armap %t.lib | FileCheck %s
6+
7+
!ELF
8+
FileHeader:
9+
Class: ELFCLASS64
10+
Data: ELFDATA2LSB
11+
Type: ET_EXEC
12+
Machine: EM_X86_64
13+
Sections:
14+
- Name: .data
15+
Type: SHT_PROGBITS
16+
Flags: [ SHF_ALLOC ]
17+
AddressAlign: 0x0000000000000001
18+
Content: "00"
19+
Size: 2147483648
20+
21+
# CHECK: Archive map
22+
# CHECK-NEXT: main in trivial-object-test.elf-x86-64
23+
24+
# CHECK: archive-SYM64-write.test.tmp:
25+
26+
# CHECK: archive-SYM64-write.test.tmp2:
27+
28+
# CHECK: trivial-object-test.elf-x86-64:
29+
# CHECK-NEXT: U SomeOtherFunction
30+
# CHECK-NEXT: 0000000000000000 T main
31+
# CHECK-NEXT: U puts

0 commit comments

Comments
 (0)