Reland "[llvm] Add symbol table support to llvm-objcopy"

This change adds support for SHT_SYMTAB sections.

Patch by Jake Ehrlich

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

llvm-svn: 311974
This commit is contained in:
Petr Hosek 2017-08-29 02:12:03 +00:00
parent de8ef1393d
commit 79cee9e784
3 changed files with 240 additions and 0 deletions

View File

@ -0,0 +1,93 @@
# RUN: yaml2obj %s > %t
# RUN: llvm-objcopy %t %t2
# RUN: llvm-readobj -symbols %t2 | FileCheck %s
!ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_EXEC
Machine: EM_X86_64
Sections:
- Name: .text
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
Address: 0x1000
AddressAlign: 0x0000000000000010
Content: "0000000000000000"
- Name: .data
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC ]
Address: 0x2000
AddressAlign: 0x0000000000000010
Content: "0000000000000000"
Symbols:
Global:
- Name: _start
Type: STT_FUNC
Section: .text
Value: 0x1000
Size: 4
- Name: foo
Type: STT_FUNC
Section: .text
Section: .text
Value: 0x1004
- Name: bar
Type: STT_OBJECT
Section: .data
Value: 0x2000
Size: 4
- Name: baz
Type: STT_OBJECT
Section: .data
Value: 0x2004
Size: 4
#CHECK: Symbols [
#CHECK-NEXT: Symbol {
#CHECK-NEXT: Name:
#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: 0x1000
#CHECK-NEXT: Size: 4
#CHECK-NEXT: Binding: Global
#CHECK-NEXT: Type: Function
#CHECK-NEXT: Other: 0
#CHECK-NEXT: Section: .text
#CHECK-NEXT: }
#CHECK-NEXT: Symbol {
#CHECK-NEXT: Name: foo
#CHECK-NEXT: Value: 0x1004
#CHECK-NEXT: Size: 0
#CHECK-NEXT: Binding: Global
#CHECK-NEXT: Type: Function
#CHECK-NEXT: Other: 0
#CHECK-NEXT: Section: .text
#CHECK-NEXT: }
#CHECK-NEXT: Symbol {
#CHECK-NEXT: Name: bar
#CHECK-NEXT: Value: 0x2000
#CHECK-NEXT: Size: 4
#CHECK-NEXT: Binding: Global
#CHECK-NEXT: Type: Object
#CHECK-NEXT: Other: 0
#CHECK-NEXT: Section: .data
#CHECK-NEXT: }
#CHECK-NEXT: Symbol {
#CHECK-NEXT: Name: baz
#CHECK-NEXT: Value: 0x2004
#CHECK-NEXT: Size: 4
#CHECK-NEXT: Binding: Global
#CHECK-NEXT: Type: Object
#CHECK-NEXT: Other: 0
#CHECK-NEXT: Section: .data
#CHECK-NEXT: }
#CHECK-NEXT:]

View File

@ -90,6 +90,70 @@ void StringTableSection::writeSection(FileOutputBuffer &Out) const {
StrTabBuilder.write(Out.getBufferStart() + Offset);
}
void SymbolTableSection::addSymbol(StringRef Name, uint8_t Bind, uint8_t Type,
SectionBase *DefinedIn, uint64_t Value,
uint64_t Sz) {
Symbol Sym;
Sym.Name = Name;
Sym.Binding = Bind;
Sym.Type = Type;
Sym.DefinedIn = DefinedIn;
Sym.Value = Value;
Sym.Size = Sz;
Sym.Index = Symbols.size();
Symbols.emplace_back(llvm::make_unique<Symbol>(Sym));
Size += this->EntrySize;
}
void SymbolTableSection::finalize() {
// Make sure SymbolNames is finalized before getting name indexes.
SymbolNames->finalize();
uint32_t MaxLocalIndex = 0;
for (auto &Sym : Symbols) {
Sym->NameIndex = SymbolNames->findIndex(Sym->Name);
if (Sym->Binding == STB_LOCAL)
MaxLocalIndex = std::max(MaxLocalIndex, Sym->Index);
}
// Now we need to set the Link and Info fields.
Link = SymbolNames->Index;
Info = MaxLocalIndex + 1;
}
void SymbolTableSection::addSymbolNames() {
// Add all of our strings to SymbolNames so that SymbolNames has the right
// size before layout is decided.
for (auto &Sym : Symbols)
SymbolNames->addString(Sym->Name);
}
const Symbol *SymbolTableSection::getSymbolByIndex(uint32_t Index) const {
if (Symbols.size() <= Index)
error("Invalid symbol index: " + Twine(Index));
return Symbols[Index].get();
}
template <class ELFT>
void SymbolTableSectionImpl<ELFT>::writeSection(
llvm::FileOutputBuffer &Out) const {
uint8_t *Buf = Out.getBufferStart();
Buf += Offset;
typename ELFT::Sym *Sym = reinterpret_cast<typename ELFT::Sym *>(Buf);
// Loop though symbols setting each entry of the symbol table.
for (auto &Symbol : Symbols) {
Sym->st_name = Symbol->NameIndex;
Sym->st_value = Symbol->Value;
Sym->st_size = Symbol->Size;
Sym->setBinding(Symbol->Binding);
Sym->setType(Symbol->Type);
if (Symbol->DefinedIn)
Sym->st_shndx = Symbol->DefinedIn->Index;
else
Sym->st_shndx = SHN_UNDEF;
++Sym;
}
}
// Returns true IFF a section is wholly inside the range of a segment
static bool sectionWithinSegment(const SectionBase &Section,
const Segment &Segment) {
@ -132,6 +196,40 @@ void Object<ELFT>::readProgramHeaders(const ELFFile<ELFT> &ElfFile) {
}
}
template <class ELFT>
void Object<ELFT>::initSymbolTable(const llvm::object::ELFFile<ELFT> &ElfFile,
SymbolTableSection *SymTab) {
SymTab->Size = 0;
if (SymbolTable->Link - 1 >= Sections.size())
error("Symbol table has link index of " + Twine(SymbolTable->Link) +
" which is not a valid index");
if (auto StrTab =
dyn_cast<StringTableSection>(Sections[SymbolTable->Link - 1].get()))
SymTab->setStrTab(StrTab);
else
error("Symbol table has link index of " + Twine(SymbolTable->Link) +
"which is not a string table");
const Elf_Shdr &Shdr = *unwrapOrError(ElfFile.getSection(SymTab->Index));
StringRef StrTabData = unwrapOrError(ElfFile.getStringTableForSymtab(Shdr));
for (const auto &Sym : unwrapOrError(ElfFile.symbols(&Shdr))) {
SectionBase *DefSection = nullptr;
StringRef Name = unwrapOrError(Sym.getName(StrTabData));
if (Sym.st_shndx != SHN_UNDEF) {
if (Sym.st_shndx >= Sections.size())
error("Symbol '" + Name +
"' is defined in invalid section with index " +
Twine(Sym.st_shndx));
DefSection = Sections[Sym.st_shndx - 1].get();
}
SymTab->addSymbol(Name, Sym.getBinding(), Sym.getType(), DefSection,
Sym.getValue(), Sym.st_size);
}
}
template <class ELFT>
std::unique_ptr<SectionBase>
Object<ELFT>::makeSection(const llvm::object::ELFFile<ELFT> &ElfFile,
@ -140,6 +238,11 @@ Object<ELFT>::makeSection(const llvm::object::ELFFile<ELFT> &ElfFile,
switch (Shdr.sh_type) {
case SHT_STRTAB:
return llvm::make_unique<StringTableSection>();
case SHT_SYMTAB: {
auto SymTab = llvm::make_unique<SymbolTableSectionImpl<ELFT>>();
SymbolTable = SymTab.get();
return std::move(SymTab);
}
case SHT_NOBITS:
return llvm::make_unique<Section>(Data);
default:
@ -171,6 +274,11 @@ void Object<ELFT>::readSectionHeaders(const ELFFile<ELFT> &ElfFile) {
Sec->Index = Index++;
Sections.push_back(std::move(Sec));
}
// Now that all of the sections have been added we can fill out some extra
// details about symbol tables.
if (SymbolTable)
initSymbolTable(ElfFile, SymbolTable);
}
template <class ELFT> Object<ELFT>::Object(const ELFObjectFile<ELFT> &Obj) {
@ -315,9 +423,12 @@ template <class ELFT> void ELFObject<ELFT>::write(FileOutputBuffer &Out) const {
}
template <class ELFT> void ELFObject<ELFT>::finalize() {
// Make sure we add the names of all the sections.
for (const auto &Section : this->Sections) {
this->SectionNames->addString(Section->Name);
}
// Make sure we add the names of all the symbols.
this->SymbolTable->addSymbolNames();
sortSections();
assignOffsets();

View File

@ -113,6 +113,39 @@ public:
}
};
struct Symbol {
uint8_t Binding;
SectionBase *DefinedIn;
uint32_t Index;
llvm::StringRef Name;
uint32_t NameIndex;
uint64_t Size;
uint8_t Type;
uint64_t Value;
};
class SymbolTableSection : public SectionBase {
protected:
std::vector<std::unique_ptr<Symbol>> Symbols;
StringTableSection *SymbolNames;
public:
void setStrTab(StringTableSection *StrTab) { SymbolNames = StrTab; }
void addSymbol(llvm::StringRef Name, uint8_t Bind, uint8_t Type,
SectionBase *DefinedIn, uint64_t Value, uint64_t Sz);
void addSymbolNames();
const Symbol *getSymbolByIndex(uint32_t Index) const;
void finalize() override;
static bool classof(const SectionBase *S) {
return S->Type == llvm::ELF::SHT_SYMTAB;
}
};
// Only writeSection depends on the ELF type so we implement it in a subclass.
template <class ELFT> class SymbolTableSectionImpl : public SymbolTableSection {
void writeSection(llvm::FileOutputBuffer &Out) const override;
};
template <class ELFT> class Object {
private:
typedef std::unique_ptr<SectionBase> SecPtr;
@ -122,6 +155,8 @@ private:
typedef typename ELFT::Ehdr Elf_Ehdr;
typedef typename ELFT::Phdr Elf_Phdr;
void initSymbolTable(const llvm::object::ELFFile<ELFT> &ElfFile,
SymbolTableSection *SymTab);
SecPtr makeSection(const llvm::object::ELFFile<ELFT> &ElfFile,
const Elf_Shdr &Shdr);
void readProgramHeaders(const llvm::object::ELFFile<ELFT> &ElfFile);
@ -129,6 +164,7 @@ private:
protected:
StringTableSection *SectionNames;
SymbolTableSection *SymbolTable;
std::vector<SecPtr> Sections;
std::vector<SegPtr> Segments;