Skip to content

Commit 6d328d3

Browse files
committedSep 16, 2015
[ELF2] Initial support for local symbols.
Symbol table is now populated correctly, but some fields are missing, they'll be added in the future. This patch also adds --discard-all flag, which was the default behavior until now. Differential Revision: http://reviews.llvm.org/D12874 llvm-svn: 247849
1 parent 67bff0d commit 6d328d3

File tree

10 files changed

+230
-18
lines changed

10 files changed

+230
-18
lines changed
 

‎lld/ELF/Config.h

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ struct Configuration {
2020
llvm::StringRef DynamicLinker;
2121
std::string RPath;
2222
bool Shared = false;
23+
bool DiscardAll = false;
2324
};
2425

2526
extern Configuration *Config;

‎lld/ELF/Driver.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
8282
if (Args.hasArg(OPT_shared))
8383
Config->Shared = true;
8484

85+
if (Args.hasArg(OPT_discard_all))
86+
Config->DiscardAll = true;
87+
8588
// Create a list of input files.
8689
std::vector<MemoryBufferRef> Inputs;
8790

‎lld/ELF/InputFiles.cpp

+23-7
Original file line numberDiff line numberDiff line change
@@ -55,21 +55,36 @@ template <class ELFT> void ELFData<ELFT>::openELF(MemoryBufferRef MB) {
5555
}
5656

5757
template <class ELFT>
58-
typename ELFData<ELFT>::Elf_Sym_Range ELFData<ELFT>::getNonLocalSymbols() {
58+
typename ELFData<ELFT>::Elf_Sym_Range
59+
ELFData<ELFT>::getSymbolsHelper(bool Local) {
5960
if (!Symtab)
6061
return Elf_Sym_Range(nullptr, nullptr);
62+
Elf_Sym_Range Syms = ELFObj->symbols(Symtab);
63+
uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end());
64+
uint32_t FirstNonLocal = Symtab->sh_info;
65+
if (FirstNonLocal > NumSymbols)
66+
error("Invalid sh_info in symbol table");
67+
if (!Local)
68+
return llvm::make_range(Syms.begin() + FirstNonLocal, Syms.end());
69+
else
70+
// Skip over dummy symbol.
71+
return llvm::make_range(Syms.begin() + 1, Syms.begin() + FirstNonLocal);
72+
}
6173

74+
template <class ELFT>
75+
typename ELFData<ELFT>::Elf_Sym_Range ELFData<ELFT>::getNonLocalSymbols() {
76+
if (!Symtab)
77+
return Elf_Sym_Range(nullptr, nullptr);
6278
ErrorOr<StringRef> StringTableOrErr =
6379
ELFObj->getStringTableForSymtab(*Symtab);
6480
error(StringTableOrErr.getError());
6581
StringTable = *StringTableOrErr;
82+
return getSymbolsHelper(false);
83+
}
6684

67-
Elf_Sym_Range Syms = ELFObj->symbols(Symtab);
68-
uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end());
69-
uint32_t FirstNonLocal = Symtab->sh_info;
70-
if (FirstNonLocal > NumSymbols)
71-
error("Invalid sh_info in symbol table");
72-
return llvm::make_range(Syms.begin() + FirstNonLocal, Syms.end());
85+
template <class ELFT>
86+
typename ObjectFile<ELFT>::Elf_Sym_Range ObjectFile<ELFT>::getLocalSymbols() {
87+
return this->getSymbolsHelper(true);
7388
}
7489

7590
template <class ELFT> void elf2::ObjectFile<ELFT>::parse() {
@@ -217,6 +232,7 @@ template <class ELFT> void SharedFile<ELFT>::parse() {
217232

218233
namespace lld {
219234
namespace elf2 {
235+
220236
template class elf2::ObjectFile<llvm::object::ELF32LE>;
221237
template class elf2::ObjectFile<llvm::object::ELF32BE>;
222238
template class elf2::ObjectFile<llvm::object::ELF64LE>;

‎lld/ELF/InputFiles.h

+5
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,14 @@ template <class ELFT> class ELFData {
102102

103103
uint16_t getEMachine() const { return getObj()->getHeader()->e_machine; }
104104

105+
StringRef getStringTable() const { return StringTable; }
106+
105107
protected:
106108
std::unique_ptr<llvm::object::ELFFile<ELFT>> ELFObj;
107109
const Elf_Shdr *Symtab = nullptr;
108110
StringRef StringTable;
109111
Elf_Sym_Range getNonLocalSymbols();
112+
Elf_Sym_Range getSymbolsHelper(bool);
110113

111114
void openELF(MemoryBufferRef MB);
112115
};
@@ -138,6 +141,8 @@ class ObjectFile : public ObjectFileBase, public ELFData<ELFT> {
138141
return SymbolBodies[SymbolIndex - FirstNonLocal]->getReplacement();
139142
}
140143

144+
Elf_Sym_Range getLocalSymbols();
145+
141146
private:
142147
void initializeChunks();
143148
void initializeSymbols();

‎lld/ELF/Options.td

+3
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,6 @@ def rpath : Separate<["-"], "rpath">,
1515

1616
def shared : Flag<["-"], "shared">,
1717
HelpText<"Build a shared object">;
18+
19+
def discard_all : Flag<["-"], "discard-all">,
20+
HelpText<"Delete all local symbols">;

‎lld/ELF/Writer.cpp

+38-9
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ template <class ELFT>
210210
class SymbolTableSection final : public OutputSectionBase<ELFT::Is64Bits> {
211211
public:
212212
typedef typename ELFFile<ELFT>::Elf_Sym Elf_Sym;
213+
typedef typename ELFFile<ELFT>::Elf_Sym_Range Elf_Sym_Range;
213214
typedef typename OutputSectionBase<ELFT::Is64Bits>::uintX_t uintX_t;
214215
SymbolTableSection(Writer<ELFT> &W, SymbolTable &Table,
215216
StringTableSection<ELFT::Is64Bits> &StrTabSec)
@@ -221,25 +222,25 @@ class SymbolTableSection final : public OutputSectionBase<ELFT::Is64Bits> {
221222
typedef OutputSectionBase<ELFT::Is64Bits> Base;
222223
typename Base::HeaderT &Header = this->Header;
223224

224-
// For now the only local symbol is going to be the one at index 0
225-
Header.sh_info = 1;
226-
227225
Header.sh_entsize = sizeof(Elf_Sym);
228226
Header.sh_addralign = ELFT::Is64Bits ? 8 : 4;
229227
}
230228

231229
void finalize() override {
232230
this->Header.sh_size = getNumSymbols() * sizeof(Elf_Sym);
233231
this->Header.sh_link = StrTabSec.getSectionIndex();
232+
this->Header.sh_info = NumLocals + 1;
234233
}
235234

236235
void writeTo(uint8_t *Buf) override;
237236

238237
const SymbolTable &getSymTable() const { return Table; }
239238

240-
void addSymbol(StringRef Name) {
239+
void addSymbol(StringRef Name, bool isLocal = false) {
241240
StrTabSec.add(Name);
242241
++NumVisible;
242+
if (isLocal)
243+
++NumLocals;
243244
}
244245

245246
StringTableSection<ELFT::Is64Bits> &getStrTabSec() { return StrTabSec; }
@@ -249,6 +250,7 @@ class SymbolTableSection final : public OutputSectionBase<ELFT::Is64Bits> {
249250
SymbolTable &Table;
250251
StringTableSection<ELFT::Is64Bits> &StrTabSec;
251252
unsigned NumVisible = 0;
253+
unsigned NumLocals = 0;
252254
const Writer<ELFT> &W;
253255
};
254256

@@ -434,6 +436,7 @@ template <class ELFT> class Writer {
434436
typedef typename ELFFile<ELFT>::Elf_Ehdr Elf_Ehdr;
435437
typedef typename ELFFile<ELFT>::Elf_Phdr Elf_Phdr;
436438
typedef typename ELFFile<ELFT>::Elf_Sym Elf_Sym;
439+
typedef typename ELFFile<ELFT>::Elf_Sym_Range Elf_Sym_Range;
437440
typedef typename ELFFile<ELFT>::Elf_Rela Elf_Rela;
438441
Writer(SymbolTable *T)
439442
: SymTabSec(*this, *T, StrTabSec), DynSymSec(*this, *T, DynStrSec),
@@ -623,9 +626,28 @@ static bool includeInSymtab(const SymbolBody &B) {
623626
}
624627

625628
template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) {
626-
uint8_t *BufStart = Buf;
627-
628629
Buf += sizeof(Elf_Sym);
630+
631+
// All symbols with STB_LOCAL binding precede the weak and global symbols.
632+
// .dynsym only contains global symbols.
633+
if (!Config->DiscardAll && !StrTabSec.isDynamic()) {
634+
for (const std::unique_ptr<ObjectFileBase> &FileB :
635+
Table.getObjectFiles()) {
636+
auto &File = cast<ObjectFile<ELFT>>(*FileB);
637+
Elf_Sym_Range Syms = File.getLocalSymbols();
638+
for (const Elf_Sym &Sym : Syms) {
639+
auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
640+
ErrorOr<StringRef> SymName = Sym.getName(File.getStringTable());
641+
ESym->st_name = (SymName) ? StrTabSec.getFileOff(*SymName) : 0;
642+
ESym->st_value = Sym.st_value;
643+
ESym->st_size = Sym.st_size;
644+
Buf += sizeof(Elf_Sym);
645+
}
646+
}
647+
}
648+
649+
uint8_t *GlobalStart = Buf;
650+
629651
for (auto &P : Table.getSymbols()) {
630652
StringRef Name = P.first;
631653
Symbol *Sym = P.second;
@@ -686,9 +708,8 @@ template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) {
686708
// The default hashing of StringRef produces different results on 32 and 64
687709
// bit systems so we sort by st_name. That is arbitrary but deterministic.
688710
// FIXME: Experiment with passing in a custom hashing instead.
689-
auto *Syms = reinterpret_cast<Elf_Sym *>(BufStart);
690-
++Syms;
691-
array_pod_sort(Syms, Syms + NumVisible, compareSym<ELFT>);
711+
auto *Syms = reinterpret_cast<Elf_Sym *>(GlobalStart);
712+
array_pod_sort(Syms, Syms + NumVisible - NumLocals, compareSym<ELFT>);
692713
}
693714

694715
template <bool Is64Bits>
@@ -819,6 +840,14 @@ template <class ELFT> void Writer<ELFT>::createSections() {
819840

820841
for (const std::unique_ptr<ObjectFileBase> &FileB : Symtab.getObjectFiles()) {
821842
auto &File = cast<ObjectFile<ELFT>>(*FileB);
843+
if (!Config->DiscardAll) {
844+
Elf_Sym_Range Syms = File.getLocalSymbols();
845+
for (const Elf_Sym &Sym : Syms) {
846+
ErrorOr<StringRef> SymName = Sym.getName(File.getStringTable());
847+
if (SymName)
848+
SymTabSec.addSymbol(*SymName, true);
849+
}
850+
}
822851
for (SectionChunk<ELFT> *C : File.getChunks()) {
823852
if (!C)
824853
continue;

‎lld/test/elf2/basic64be.s

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t
2-
# RUN: lld -flavor gnu2 %t -o %t2
2+
# RUN: lld -flavor gnu2 -discard-all %t -o %t2
33
# RUN: llvm-readobj -file-headers -sections -program-headers %t2 | FileCheck %s
44
# REQUIRES: ppc
55

‎lld/test/elf2/local-dynamic.s

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// Check that local symbols are not inserted into dynamic table.
2+
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
3+
// RUN: lld -flavor gnu2 %t -shared -o %t1.so
4+
// RUN: llvm-readobj -t -dyn-symbols %t1.so | FileCheck %s
5+
// REQUIRES: x86
6+
7+
// CHECK: Symbols [
8+
// CHECK-NEXT: Symbol {
9+
// CHECK-NEXT: Name:
10+
// CHECK-NEXT: Value: 0x0
11+
// CHECK-NEXT: Size: 0
12+
// CHECK-NEXT: Binding: Local
13+
// CHECK-NEXT: Type: None
14+
// CHECK-NEXT: Other: 0
15+
// CHECK-NEXT: Section: Undefined
16+
// CHECK-NEXT: }
17+
// CHECK-NEXT: Symbol {
18+
// CHECK-NEXT: Name: blah
19+
// CHECK-NEXT: Value: 0x0
20+
// CHECK-NEXT: Size: 0
21+
// CHECK-NEXT: Binding: Local
22+
// CHECK-NEXT: Type: None
23+
// CHECK-NEXT: Other: 0
24+
// CHECK-NEXT: Section: Undefined
25+
// CHECK-NEXT: }
26+
// CHECK-NEXT: Symbol {
27+
// CHECK-NEXT: Name: foo
28+
// CHECK-NEXT: Value: 0x0
29+
// CHECK-NEXT: Size: 0
30+
// CHECK-NEXT: Binding: Local
31+
// CHECK-NEXT: Type: None
32+
// CHECK-NEXT: Other: 0
33+
// CHECK-NEXT: Section: Undefined
34+
// CHECK-NEXT: }
35+
// CHECK-NEXT: Symbol {
36+
// CHECK-NEXT: Name: goo
37+
// CHECK-NEXT: Value: 0x0
38+
// CHECK-NEXT: Size: 0
39+
// CHECK-NEXT: Binding: Local
40+
// CHECK-NEXT: Type: None
41+
// CHECK-NEXT: Other: 0
42+
// CHECK-NEXT: Section: Undefined
43+
// CHECK-NEXT: }
44+
// CHECK-NEXT: Symbol {
45+
// CHECK-NEXT: Name: _start
46+
// CHECK-NEXT: Value: 0x1000
47+
// CHECK-NEXT: Size: 0
48+
// CHECK-NEXT: Binding: Global
49+
// CHECK-NEXT: Type: None
50+
// CHECK-NEXT: Other: 0
51+
// CHECK-NEXT: Section: .text
52+
// CHECK-NEXT: }
53+
// CHECK-NEXT: ]
54+
55+
// CHECK: DynamicSymbols [
56+
// CHECK-NEXT: Symbol {
57+
// CHECK-NEXT: Name: @
58+
// CHECK-NEXT: Value: 0x0
59+
// CHECK-NEXT: Size: 0
60+
// CHECK-NEXT: Binding: Local
61+
// CHECK-NEXT: Type: None
62+
// CHECK-NEXT: Other: 0
63+
// CHECK-NEXT: Section: Undefined
64+
// CHECK-NEXT: }
65+
// CHECK-NEXT: Symbol {
66+
// CHECK-NEXT: Name: _start@
67+
// CHECK-NEXT: Value: 0x1000
68+
// CHECK-NEXT: Size: 0
69+
// CHECK-NEXT: Binding: Global
70+
// CHECK-NEXT: Type: None
71+
// CHECK-NEXT: Other: 0
72+
// CHECK-NEXT: Section: .text
73+
// CHECK-NEXT: }
74+
// CHECK-NEXT: ]
75+
76+
.global _start
77+
_start:
78+
79+
blah:
80+
foo:
81+
goo:
82+
83+

‎lld/test/elf2/local.s

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Check that symbol table is correctly populated with local symbols.
2+
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
3+
// RUN: lld -flavor gnu2 %t -o %t1
4+
// RUN: llvm-readobj -t -s %t1 | FileCheck %s
5+
// REQUIRES: x86
6+
7+
// Check that Info is equal to the number of local symbols.
8+
// CHECK: Section {
9+
// CHECK: Name: .symtab
10+
// CHECK-NEXT: Type: SHT_SYMTAB
11+
// CHECK-NEXT: Flags [
12+
// CHECK-NEXT: ]
13+
// CHECK-NEXT: Address:
14+
// CHECK-NEXT: Offset:
15+
// CHECK-NEXT: Size:
16+
// CHECK-NEXT: Link:
17+
// CHECK-NEXT: Info: 4
18+
19+
// CHECK: Symbols [
20+
// CHECK-NEXT: Symbol {
21+
// CHECK-NEXT: Name:
22+
// CHECK-NEXT: Value: 0x0
23+
// CHECK-NEXT: Size: 0
24+
// CHECK-NEXT: Binding: Local
25+
// CHECK-NEXT: Type: None
26+
// CHECK-NEXT: Other: 0
27+
// CHECK-NEXT: Section: Undefined
28+
// CHECK-NEXT: }
29+
// CHECK-NEXT: Symbol {
30+
// CHECK-NEXT: Name: blah
31+
// CHECK-NEXT: Value: 0x0
32+
// CHECK-NEXT: Size: 0
33+
// CHECK-NEXT: Binding: Local
34+
// CHECK-NEXT: Type: None
35+
// CHECK-NEXT: Other: 0
36+
// CHECK-NEXT: Section: Undefined
37+
// CHECK-NEXT: }
38+
// CHECK-NEXT: Symbol {
39+
// CHECK-NEXT: Name: foo
40+
// CHECK-NEXT: Value: 0x0
41+
// CHECK-NEXT: Size: 0
42+
// CHECK-NEXT: Binding: Local
43+
// CHECK-NEXT: Type: None
44+
// CHECK-NEXT: Other: 0
45+
// CHECK-NEXT: Section: Undefined
46+
// CHECK-NEXT: }
47+
// CHECK-NEXT: Symbol {
48+
// CHECK-NEXT: Name: goo
49+
// CHECK-NEXT: Value: 0x0
50+
// CHECK-NEXT: Size: 0
51+
// CHECK-NEXT: Binding: Local
52+
// CHECK-NEXT: Type: None
53+
// CHECK-NEXT: Other: 0
54+
// CHECK-NEXT: Section: Undefined
55+
// CHECK-NEXT: }
56+
// CHECK-NEXT: Symbol {
57+
// CHECK-NEXT: Name: _start
58+
// CHECK-NEXT: Value: 0x11000
59+
// CHECK-NEXT: Size: 0
60+
// CHECK-NEXT: Binding: Global
61+
// CHECK-NEXT: Type: None
62+
// CHECK-NEXT: Other: 0
63+
// CHECK-NEXT: Section: .text
64+
// CHECK-NEXT: }
65+
// CHECK-NEXT: ]
66+
67+
.global _start
68+
_start:
69+
70+
blah:
71+
foo:
72+
goo:

‎lld/test/elf2/resolution.s

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
22
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/resolution.s -o %t2
3-
// RUN: lld -flavor gnu2 %t %t2 -o %t3
3+
// RUN: lld -flavor gnu2 -discard-all %t %t2 -o %t3
44
// RUN: llvm-readobj -t %t3 | FileCheck %s
55
// REQUIRES: x86
66

0 commit comments

Comments
 (0)
Please sign in to comment.