Index: ELF/InputFiles.h =================================================================== --- ELF/InputFiles.h +++ ELF/InputFiles.h @@ -102,6 +102,8 @@ uint16_t getEMachine() const { return getObj()->getHeader()->e_machine; } + StringRef getStringTable() const { return StringTable; } + protected: std::unique_ptr> ELFObj; const Elf_Shdr *Symtab = nullptr; @@ -138,6 +140,8 @@ return SymbolBodies[SymbolIndex - FirstNonLocal]->getReplacement(); } + Elf_Sym_Range getLocalSymbols(); + private: void initializeChunks(); void initializeSymbols(); Index: ELF/InputFiles.cpp =================================================================== --- ELF/InputFiles.cpp +++ ELF/InputFiles.cpp @@ -72,6 +72,24 @@ return llvm::make_range(Syms.begin() + FirstNonLocal, Syms.end()); } +template +typename ObjectFile::Elf_Sym_Range ObjectFile::getLocalSymbols() { + if (!this->Symtab) + return Elf_Sym_Range(nullptr, nullptr); + Elf_Sym_Range Syms = this->ELFObj->symbols(this->Symtab); + uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end()); + uint32_t LastLocal = this->Symtab->sh_info - 1; + if (LastLocal > NumSymbols) + error("Invalid sh_info in symbol table"); + + // No local symbols. + if (LastLocal == 0) + return llvm::make_range(nullptr, nullptr); + + // Skip over dummy symbol. + return llvm::make_range(Syms.begin() + 1, Syms.begin() + LastLocal + 1); +} + template void elf2::ObjectFile::parse() { this->openELF(MB); Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -158,6 +158,7 @@ class SymbolTableSection final : public OutputSectionBase { public: typedef typename ELFFile::Elf_Sym Elf_Sym; + typedef typename ELFFile::Elf_Sym_Range Elf_Sym_Range; typedef typename OutputSectionBase::uintX_t uintX_t; SymbolTableSection(Writer &W, SymbolTable &Table, StringTableSection &StrTabSec) @@ -169,9 +170,6 @@ typedef OutputSectionBase Base; typename Base::HeaderT &Header = this->Header; - // For now the only local symbol is going to be the one at index 0 - Header.sh_info = 1; - Header.sh_entsize = sizeof(Elf_Sym); Header.sh_addralign = ELFT::Is64Bits ? 8 : 4; } @@ -179,15 +177,18 @@ void finalize() override { this->Header.sh_size = getNumSymbols() * sizeof(Elf_Sym); this->Header.sh_link = StrTabSec.getSectionIndex(); + this->Header.sh_info = NumLocals + 1; } void writeTo(uint8_t *Buf) override; const SymbolTable &getSymTable() const { return Table; } - void addSymbol(StringRef Name) { + void addSymbol(StringRef Name, bool isLocal = false) { StrTabSec.add(Name); ++NumVisible; + if (isLocal) + ++NumLocals; } StringTableSection &getStrTabSec() { return StrTabSec; } @@ -197,6 +198,7 @@ SymbolTable &Table; StringTableSection &StrTabSec; unsigned NumVisible = 0; + unsigned NumLocals = 0; const Writer &W; }; @@ -363,6 +365,7 @@ typedef typename ELFFile::Elf_Ehdr Elf_Ehdr; typedef typename ELFFile::Elf_Phdr Elf_Phdr; typedef typename ELFFile::Elf_Sym Elf_Sym; + typedef typename ELFFile::Elf_Sym_Range Elf_Sym_Range; Writer(SymbolTable *T) : SymTabSec(*this, *T, StrTabSec), DynSymSec(*this, *T, DynStrSec), HashSec(DynSymSec), DynamicSec(*T, HashSec) {} @@ -529,9 +532,24 @@ } template void SymbolTableSection::writeTo(uint8_t *Buf) { + Buf += sizeof(Elf_Sym); + + // Local symbols precede other symbols. + for (const std::unique_ptr &FileB : Table.getObjectFiles()) { + auto &File = cast>(*FileB); + Elf_Sym_Range Syms = File.getLocalSymbols(); + for (const Elf_Sym &Sym: Syms) { + auto *ESym = reinterpret_cast(Buf); + ErrorOr SymName = Sym.getName(File.getStringTable()); + ESym->st_name = (SymName) ? StrTabSec.getFileOff(*SymName) : 0; + ESym->st_value = Sym.st_value; + ESym->st_size = Sym.st_size; + Buf += sizeof(Elf_Sym); + } + } + uint8_t *BufStart = Buf; - Buf += sizeof(Elf_Sym); for (auto &P : Table.getSymbols()) { StringRef Name = P.first; Symbol *Sym = P.second; @@ -593,8 +611,7 @@ // bit systems so we sort by st_name. That is arbitrary but deterministic. // FIXME: Experiment with passing in a custom hashing instead. auto *Syms = reinterpret_cast(BufStart); - ++Syms; - array_pod_sort(Syms, Syms + NumVisible, compareSym); + array_pod_sort(Syms, Syms + NumVisible - NumLocals, compareSym); } template @@ -672,6 +689,12 @@ const SymbolTable &Symtab = SymTabSec.getSymTable(); for (const std::unique_ptr &FileB : Symtab.getObjectFiles()) { auto &File = cast>(*FileB); + Elf_Sym_Range Syms = File.getLocalSymbols(); + for (const Elf_Sym &Sym: Syms) { + ErrorOr SymName = Sym.getName(File.getStringTable()); + if (SymName) + SymTabSec.addSymbol(*SymName, true); + } for (SectionChunk *C : File.getChunks()) { if (!C) continue; Index: test/elf2/basic64be.s =================================================================== --- test/elf2/basic64be.s +++ test/elf2/basic64be.s @@ -30,7 +30,7 @@ # CHECK-NEXT: Version: 1 # CHECK-NEXT: Entry: 0x12000 # CHECK-NEXT: ProgramHeaderOffset: 0x40 -# CHECK-NEXT: SectionHeaderOffset: 0x2078 +# CHECK-NEXT: SectionHeaderOffset: 0x2090 # CHECK-NEXT: Flags [ (0x0) # CHECK-NEXT: ] # CHECK-NEXT: HeaderSize: 64 @@ -127,9 +127,9 @@ # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x0 # CHECK-NEXT: Offset: 0x2018 -# CHECK-NEXT: Size: 48 +# CHECK-NEXT: Size: 72 # CHECK-NEXT: Link: 6 -# CHECK-NEXT: Info: 1 +# CHECK-NEXT: Info: 2 # CHECK-NEXT: AddressAlignment: 8 # CHECK-NEXT: EntrySize: 24 # CHECK-NEXT: } @@ -140,7 +140,7 @@ # CHECK-NEXT: Flags [ (0x0) # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x0 -# CHECK-NEXT: Offset: 0x2048 +# CHECK-NEXT: Offset: 0x2060 # CHECK-NEXT: Size: 46 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 Index: test/elf2/local.s =================================================================== --- test/elf2/local.s +++ test/elf2/local.s @@ -0,0 +1,74 @@ +// Check that symbol table is correctly populated with local symbols. +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t +// RUN: lld -flavor gnu2 %t -o %t1 +// RUN: llvm-readobj -t -s %t1 | FileCheck %s +// REQUIRES: x86 + +// CHECK: Section { +// CHECK: Index: 4 +// CHECK: Name: .symtab (40) +// CHECK: Type: SHT_SYMTAB (0x2) +// CHECK: Flags [ (0x0) +// CHECK: ] +// CHECK: Address: 0x0 +// CHECK: Offset: 0x1000 +// CHECK: Size: 120 +// CHECK: Link: 5 +// CHECK: Info: 4 +// CHECK: AddressAlignment: 8 +// CHECK: EntrySize: 24 +// CHECK: } +// CHECK: Symbols [ +// CHECK: Symbol { +// CHECK: Name: (0) +// CHECK: Value: 0x0 +// CHECK: Size: 0 +// CHECK: Binding: Local (0x0) +// CHECK: Type: None (0x0) +// CHECK: Other: 0 +// CHECK: Section: Undefined (0x0) +// CHECK: } +// CHECK: Symbol { +// CHECK: Name: blah (27) +// CHECK: Value: 0x0 +// CHECK: Size: 0 +// CHECK: Binding: Local (0x0) +// CHECK: Type: None (0x0) +// CHECK: Other: 0 +// CHECK: Section: Undefined (0x0) +// CHECK: } +// CHECK: Symbol { +// CHECK: Name: foo (23) +// CHECK: Value: 0x0 +// CHECK: Size: 0 +// CHECK: Binding: Local (0x0) +// CHECK: Type: None (0x0) +// CHECK: Other: 0 +// CHECK: Section: Undefined (0x0) +// CHECK: } +// CHECK: Symbol { +// CHECK: Name: goo (19) +// CHECK: Value: 0x0 +// CHECK: Size: 0 +// CHECK: Binding: Local (0x0) +// CHECK: Type: None (0x0) +// CHECK: Other: 0 +// CHECK: Section: Undefined (0x0) +// CHECK: } +// CHECK: Symbol { +// CHECK: Name: _start (7) +// CHECK: Value: 0x11000 +// CHECK: Size: 0 +// CHECK: Binding: Global (0x1) +// CHECK: Type: None (0x0) +// CHECK: Other: 0 +// CHECK: Section: .text (0x1) +// CHECK: } +// CHECK: ] + +.globl _start +_start: + +blah: +foo: +goo: Index: test/elf2/resolution.s =================================================================== --- test/elf2/resolution.s +++ test/elf2/resolution.s @@ -19,6 +19,24 @@ // CHECK-NEXT: Section: Undefined (0x0) // CHECK-NEXT: } // CHECK-NEXT: Symbol { +// CHECK-NEXT: Name: local +// CHECK-NEXT: Value: 0x1 +// CHECK-NEXT: Size: 0 +// CHECK-NEXT: Binding: Local +// CHECK-NEXT: Type: None +// CHECK-NEXT: Other: 0 +// CHECK-NEXT: Section: Undefined +// CHECK-NEXT: } +// CHECK-NEXT: Symbol { +// CHECK-NEXT: Name: local +// CHECK-NEXT: Value: 0x0 +// CHECK-NEXT: Size: 0 +// CHECK-NEXT: Binding: Local +// CHECK-NEXT: Type: None +// CHECK-NEXT: Other: 0 +// CHECK-NEXT: Section: Undefined +// CHECK-NEXT: } +// CHECK-NEXT: Symbol { // CHECK-NEXT: Name: _start // CHECK-NEXT: Value: // CHECK-NEXT: Size: 0