mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 03:02:36 +01:00
[Object] Add {begin,end}_dynamic_symbols stubs and implementation for ELF.
Add -D option to llvm-nm to dump dynamic symbols. Patch by David Meyer. llvm-svn: 151600
This commit is contained in:
parent
2eec1f2ac0
commit
0aef1b9f18
@ -152,6 +152,8 @@ public:
|
||||
COFFObjectFile(MemoryBuffer *Object, error_code &ec);
|
||||
virtual symbol_iterator begin_symbols() const;
|
||||
virtual symbol_iterator end_symbols() const;
|
||||
virtual symbol_iterator begin_dynamic_symbols() const;
|
||||
virtual symbol_iterator end_dynamic_symbols() const;
|
||||
virtual section_iterator begin_sections() const;
|
||||
virtual section_iterator end_sections() const;
|
||||
|
||||
|
@ -295,6 +295,7 @@ private:
|
||||
const Elf_Shdr *SectionHeaderTable;
|
||||
const Elf_Shdr *dot_shstrtab_sec; // Section header string table.
|
||||
const Elf_Shdr *dot_strtab_sec; // Symbol header string table.
|
||||
const Elf_Shdr *dot_dynstr_sec; // Dynamic symbol string table.
|
||||
Sections_t SymbolTableSections;
|
||||
IndexMap_t SymbolTableSectionsIndexMap;
|
||||
DenseMap<const Elf_Sym*, ELF::Elf64_Word> ExtendedSymbolTable;
|
||||
@ -319,7 +320,10 @@ private:
|
||||
const Elf_Rela *getRela(DataRefImpl Rela) const;
|
||||
const char *getString(uint32_t section, uint32_t offset) const;
|
||||
const char *getString(const Elf_Shdr *section, uint32_t offset) const;
|
||||
error_code getSymbolName(const Elf_Sym *Symb, StringRef &Res) const;
|
||||
error_code getSymbolName(const Elf_Shdr *section,
|
||||
const Elf_Sym *Symb,
|
||||
StringRef &Res) const;
|
||||
void VerifyStrTab(const Elf_Shdr *sh) const;
|
||||
|
||||
protected:
|
||||
const Elf_Sym *getSymbol(DataRefImpl Symb) const; // FIXME: Should be private?
|
||||
@ -375,6 +379,8 @@ public:
|
||||
ELFObjectFile(MemoryBuffer *Object, error_code &ec);
|
||||
virtual symbol_iterator begin_symbols() const;
|
||||
virtual symbol_iterator end_symbols() const;
|
||||
virtual symbol_iterator begin_dynamic_symbols() const;
|
||||
virtual symbol_iterator end_dynamic_symbols() const;
|
||||
virtual section_iterator begin_sections() const;
|
||||
virtual section_iterator end_sections() const;
|
||||
|
||||
@ -425,10 +431,14 @@ error_code ELFObjectFile<target_endianness, is64Bits>
|
||||
// Check to see if we are at the end of this symbol table.
|
||||
if (Symb.d.a >= SymbolTableSection->getEntityCount()) {
|
||||
// We are at the end. If there are other symbol tables, jump to them.
|
||||
++Symb.d.b;
|
||||
Symb.d.a = 1; // The 0th symbol in ELF is fake.
|
||||
// If the symbol table is .dynsym, we are iterating dynamic symbols,
|
||||
// and there is only one table of these.
|
||||
if (Symb.d.b != 0) {
|
||||
++Symb.d.b;
|
||||
Symb.d.a = 1; // The 0th symbol in ELF is fake.
|
||||
}
|
||||
// Otherwise return the terminator.
|
||||
if (Symb.d.b >= SymbolTableSections.size()) {
|
||||
if (Symb.d.b == 0 || Symb.d.b >= SymbolTableSections.size()) {
|
||||
Symb.d.a = std::numeric_limits<uint32_t>::max();
|
||||
Symb.d.b = std::numeric_limits<uint32_t>::max();
|
||||
}
|
||||
@ -444,7 +454,7 @@ error_code ELFObjectFile<target_endianness, is64Bits>
|
||||
StringRef &Result) const {
|
||||
validateSymbol(Symb);
|
||||
const Elf_Sym *symb = getSymbol(Symb);
|
||||
return getSymbolName(symb, Result);
|
||||
return getSymbolName(SymbolTableSections[Symb.d.b], symb, Result);
|
||||
}
|
||||
|
||||
template<support::endianness target_endianness, bool is64Bits>
|
||||
@ -1128,7 +1138,7 @@ error_code ELFObjectFile<target_endianness, is64Bits>
|
||||
}
|
||||
const Elf_Sym *symb = getEntry<Elf_Sym>(sec->sh_link, symbol_index);
|
||||
StringRef symname;
|
||||
if (error_code ec = getSymbolName(symb, symname))
|
||||
if (error_code ec = getSymbolName(getSection(sec->sh_link), symb, symname))
|
||||
return ec;
|
||||
switch (Header->e_machine) {
|
||||
case ELF::EM_X86_64:
|
||||
@ -1156,6 +1166,16 @@ error_code ELFObjectFile<target_endianness, is64Bits>
|
||||
return object_error::success;
|
||||
}
|
||||
|
||||
// Verify that the last byte in the string table in a null.
|
||||
template<support::endianness target_endianness, bool is64Bits>
|
||||
void ELFObjectFile<target_endianness, is64Bits>
|
||||
::VerifyStrTab(const Elf_Shdr *sh) const {
|
||||
const char *strtab = (const char*)base() + sh->sh_offset;
|
||||
if (strtab[sh->sh_size - 1] != 0)
|
||||
// FIXME: Proper error handling.
|
||||
report_fatal_error("String table must end with a null terminator!");
|
||||
}
|
||||
|
||||
template<support::endianness target_endianness, bool is64Bits>
|
||||
ELFObjectFile<target_endianness, is64Bits>::ELFObjectFile(MemoryBuffer *Object
|
||||
, error_code &ec)
|
||||
@ -1163,7 +1183,8 @@ ELFObjectFile<target_endianness, is64Bits>::ELFObjectFile(MemoryBuffer *Object
|
||||
, isDyldELFObject(false)
|
||||
, SectionHeaderTable(0)
|
||||
, dot_shstrtab_sec(0)
|
||||
, dot_strtab_sec(0) {
|
||||
, dot_strtab_sec(0)
|
||||
, dot_dynstr_sec(0) {
|
||||
|
||||
const uint64_t FileSize = Data->getBufferSize();
|
||||
|
||||
@ -1194,6 +1215,10 @@ ELFObjectFile<target_endianness, is64Bits>::ELFObjectFile(MemoryBuffer *Object
|
||||
// To find the symbol tables we walk the section table to find SHT_SYMTAB.
|
||||
const Elf_Shdr* SymbolTableSectionHeaderIndex = 0;
|
||||
const Elf_Shdr* sh = SectionHeaderTable;
|
||||
|
||||
// Reserve SymbolTableSections[0] for .dynsym
|
||||
SymbolTableSections.push_back(NULL);
|
||||
|
||||
for (uint64_t i = 0, e = getNumSections(); i != e; ++i) {
|
||||
if (sh->sh_type == ELF::SHT_SYMTAB_SHNDX) {
|
||||
if (SymbolTableSectionHeaderIndex)
|
||||
@ -1205,6 +1230,13 @@ ELFObjectFile<target_endianness, is64Bits>::ELFObjectFile(MemoryBuffer *Object
|
||||
SymbolTableSectionsIndexMap[i] = SymbolTableSections.size();
|
||||
SymbolTableSections.push_back(sh);
|
||||
}
|
||||
if (sh->sh_type == ELF::SHT_DYNSYM) {
|
||||
if (SymbolTableSections[0] != NULL)
|
||||
// FIXME: Proper error handling.
|
||||
report_fatal_error("More than one .dynsym!");
|
||||
SymbolTableSectionsIndexMap[i] = 0;
|
||||
SymbolTableSections[0] = sh;
|
||||
}
|
||||
if (sh->sh_type == ELF::SHT_REL || sh->sh_type == ELF::SHT_RELA) {
|
||||
SectionRelocMap[getSection(sh->sh_info)].push_back(i);
|
||||
}
|
||||
@ -1221,10 +1253,7 @@ ELFObjectFile<target_endianness, is64Bits>::ELFObjectFile(MemoryBuffer *Object
|
||||
dot_shstrtab_sec = getSection(getStringTableIndex());
|
||||
if (dot_shstrtab_sec) {
|
||||
// Verify that the last byte in the string table in a null.
|
||||
if (((const char*)base() + dot_shstrtab_sec->sh_offset)
|
||||
[dot_shstrtab_sec->sh_size - 1] != 0)
|
||||
// FIXME: Proper error handling.
|
||||
report_fatal_error("String table must end with a null terminator!");
|
||||
VerifyStrTab(dot_shstrtab_sec);
|
||||
}
|
||||
|
||||
// Merge this into the above loop.
|
||||
@ -1239,10 +1268,13 @@ ELFObjectFile<target_endianness, is64Bits>::ELFObjectFile(MemoryBuffer *Object
|
||||
// FIXME: Proper error handling.
|
||||
report_fatal_error("Already found section named .strtab!");
|
||||
dot_strtab_sec = sh;
|
||||
const char *dot_strtab = (const char*)base() + sh->sh_offset;
|
||||
if (dot_strtab[sh->sh_size - 1] != 0)
|
||||
// FIXME: Proper error handling.
|
||||
report_fatal_error("String table must end with a null terminator!");
|
||||
VerifyStrTab(dot_strtab_sec);
|
||||
} else if (SectionName == ".dynstr") {
|
||||
if (dot_dynstr_sec != 0)
|
||||
// FIXME: Proper error handling.
|
||||
report_fatal_error("Already found section named .dynstr!");
|
||||
dot_dynstr_sec = sh;
|
||||
VerifyStrTab(dot_dynstr_sec);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1268,12 +1300,12 @@ symbol_iterator ELFObjectFile<target_endianness, is64Bits>
|
||||
::begin_symbols() const {
|
||||
DataRefImpl SymbolData;
|
||||
memset(&SymbolData, 0, sizeof(SymbolData));
|
||||
if (SymbolTableSections.size() == 0) {
|
||||
if (SymbolTableSections.size() <= 1) {
|
||||
SymbolData.d.a = std::numeric_limits<uint32_t>::max();
|
||||
SymbolData.d.b = std::numeric_limits<uint32_t>::max();
|
||||
} else {
|
||||
SymbolData.d.a = 1; // The 0th symbol in ELF is fake.
|
||||
SymbolData.d.b = 0;
|
||||
SymbolData.d.b = 1; // The 0th table is .dynsym
|
||||
}
|
||||
return symbol_iterator(SymbolRef(SymbolData, this));
|
||||
}
|
||||
@ -1288,6 +1320,31 @@ symbol_iterator ELFObjectFile<target_endianness, is64Bits>
|
||||
return symbol_iterator(SymbolRef(SymbolData, this));
|
||||
}
|
||||
|
||||
template<support::endianness target_endianness, bool is64Bits>
|
||||
symbol_iterator ELFObjectFile<target_endianness, is64Bits>
|
||||
::begin_dynamic_symbols() const {
|
||||
DataRefImpl SymbolData;
|
||||
memset(&SymbolData, 0, sizeof(SymbolData));
|
||||
if (SymbolTableSections[0] == NULL) {
|
||||
SymbolData.d.a = std::numeric_limits<uint32_t>::max();
|
||||
SymbolData.d.b = std::numeric_limits<uint32_t>::max();
|
||||
} else {
|
||||
SymbolData.d.a = 1; // The 0th symbol in ELF is fake.
|
||||
SymbolData.d.b = 0; // The 0th table is .dynsym
|
||||
}
|
||||
return symbol_iterator(SymbolRef(SymbolData, this));
|
||||
}
|
||||
|
||||
template<support::endianness target_endianness, bool is64Bits>
|
||||
symbol_iterator ELFObjectFile<target_endianness, is64Bits>
|
||||
::end_dynamic_symbols() const {
|
||||
DataRefImpl SymbolData;
|
||||
memset(&SymbolData, 0, sizeof(SymbolData));
|
||||
SymbolData.d.a = std::numeric_limits<uint32_t>::max();
|
||||
SymbolData.d.b = std::numeric_limits<uint32_t>::max();
|
||||
return symbol_iterator(SymbolRef(SymbolData, this));
|
||||
}
|
||||
|
||||
template<support::endianness target_endianness, bool is64Bits>
|
||||
section_iterator ELFObjectFile<target_endianness, is64Bits>
|
||||
::begin_sections() const {
|
||||
@ -1461,7 +1518,8 @@ const char *ELFObjectFile<target_endianness, is64Bits>
|
||||
|
||||
template<support::endianness target_endianness, bool is64Bits>
|
||||
error_code ELFObjectFile<target_endianness, is64Bits>
|
||||
::getSymbolName(const Elf_Sym *symb,
|
||||
::getSymbolName(const Elf_Shdr *section,
|
||||
const Elf_Sym *symb,
|
||||
StringRef &Result) const {
|
||||
if (symb->st_name == 0) {
|
||||
const Elf_Shdr *section = getSection(symb);
|
||||
@ -1472,8 +1530,13 @@ error_code ELFObjectFile<target_endianness, is64Bits>
|
||||
return object_error::success;
|
||||
}
|
||||
|
||||
// Use the default symbol table name section.
|
||||
Result = getString(dot_strtab_sec, symb->st_name);
|
||||
if (section == SymbolTableSections[0]) {
|
||||
// Symbol is in .dynsym, use .dynstr string table
|
||||
Result = getString(dot_dynstr_sec, symb->st_name);
|
||||
} else {
|
||||
// Use the default symbol table name section.
|
||||
Result = getString(dot_strtab_sec, symb->st_name);
|
||||
}
|
||||
return object_error::success;
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,8 @@ public:
|
||||
|
||||
virtual symbol_iterator begin_symbols() const;
|
||||
virtual symbol_iterator end_symbols() const;
|
||||
virtual symbol_iterator begin_dynamic_symbols() const;
|
||||
virtual symbol_iterator end_dynamic_symbols() const;
|
||||
virtual section_iterator begin_sections() const;
|
||||
virtual section_iterator end_sections() const;
|
||||
|
||||
|
@ -313,6 +313,9 @@ public:
|
||||
virtual symbol_iterator begin_symbols() const = 0;
|
||||
virtual symbol_iterator end_symbols() const = 0;
|
||||
|
||||
virtual symbol_iterator begin_dynamic_symbols() const = 0;
|
||||
virtual symbol_iterator end_dynamic_symbols() const = 0;
|
||||
|
||||
virtual section_iterator begin_sections() const = 0;
|
||||
virtual section_iterator end_sections() const = 0;
|
||||
|
||||
|
@ -508,6 +508,16 @@ symbol_iterator COFFObjectFile::end_symbols() const {
|
||||
return symbol_iterator(SymbolRef(ret, this));
|
||||
}
|
||||
|
||||
symbol_iterator COFFObjectFile::begin_dynamic_symbols() const {
|
||||
// TODO: implement
|
||||
report_fatal_error("Dynamic symbols unimplemented in COFFObjectFile");
|
||||
}
|
||||
|
||||
symbol_iterator COFFObjectFile::end_dynamic_symbols() const {
|
||||
// TODO: implement
|
||||
report_fatal_error("Dynamic symbols unimplemented in COFFObjectFile");
|
||||
}
|
||||
|
||||
section_iterator COFFObjectFile::begin_sections() const {
|
||||
DataRefImpl ret;
|
||||
std::memset(&ret, 0, sizeof(DataRefImpl));
|
||||
|
@ -388,6 +388,15 @@ symbol_iterator MachOObjectFile::end_symbols() const {
|
||||
return symbol_iterator(SymbolRef(DRI, this));
|
||||
}
|
||||
|
||||
symbol_iterator MachOObjectFile::begin_dynamic_symbols() const {
|
||||
// TODO: implement
|
||||
report_fatal_error("Dynamic symbols unimplemented in MachOObjectFile");
|
||||
}
|
||||
|
||||
symbol_iterator MachOObjectFile::end_dynamic_symbols() const {
|
||||
// TODO: implement
|
||||
report_fatal_error("Dynamic symbols unimplemented in MachOObjectFile");
|
||||
}
|
||||
|
||||
/*===-- Sections ----------------------------------------------------------===*/
|
||||
|
||||
|
BIN
test/Object/Inputs/shared-object-test.elf-i386
Normal file
BIN
test/Object/Inputs/shared-object-test.elf-i386
Normal file
Binary file not shown.
BIN
test/Object/Inputs/shared-object-test.elf-x86-64
Normal file
BIN
test/Object/Inputs/shared-object-test.elf-x86-64
Normal file
Binary file not shown.
31
test/Object/Inputs/shared.ll
Normal file
31
test/Object/Inputs/shared.ll
Normal file
@ -0,0 +1,31 @@
|
||||
; How to make the shared objects from this file:
|
||||
;
|
||||
; X86-32 ELF:
|
||||
; llc -mtriple=i386-linux-gnu shared.ll -filetype=obj -o tmp32.o -relocation-model=pic
|
||||
; ld -melf_i386 -shared tmp32.o -o shared-object-test.elf-i386 --unresolved-symbols=ignore-all
|
||||
;
|
||||
; X86-64 ELF:
|
||||
; llc -mtriple=x86_64-linux-gnu shared.ll -filetype=obj -o tmp64.o -relocation-model=pic
|
||||
; ld -melf_x86_64 -shared tmp64.o -o shared-object-test.elf-x86-64 --unresolved-symbols=ignore-all
|
||||
|
||||
@defined_sym = global i32 1, align 4
|
||||
|
||||
@tls_sym = thread_local global i32 2, align 4
|
||||
|
||||
@undef_sym = external global i32
|
||||
|
||||
@undef_tls_sym = external thread_local global i32
|
||||
|
||||
@common_sym = common global i32 0, align 4
|
||||
|
||||
define i32 @global_func() nounwind uwtable {
|
||||
entry:
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
declare i32 @undef_func(...)
|
||||
|
||||
define internal i32 @local_func() nounwind uwtable {
|
||||
entry:
|
||||
ret i32 0
|
||||
}
|
15
test/Object/nm-shared-object.test
Normal file
15
test/Object/nm-shared-object.test
Normal file
@ -0,0 +1,15 @@
|
||||
RUN: llvm-nm -D %p/Inputs/shared-object-test.elf-i386 \
|
||||
RUN: | FileCheck %s -check-prefix ELF
|
||||
RUN: llvm-nm -D %p/Inputs/shared-object-test.elf-x86-64 \
|
||||
RUN: | FileCheck %s -check-prefix ELF
|
||||
|
||||
; Note: tls_sym should be 'D' (not '?'), but TLS is not
|
||||
; yet recognized by ObjectFile.
|
||||
|
||||
ELF: {{[0-9a-f]+}} A __bss_start
|
||||
ELF: {{[0-9a-f]+}} A _edata
|
||||
ELF: {{[0-9a-f]+}} A _end
|
||||
ELF: {{[0-9a-f]+}} B common_sym
|
||||
ELF: {{[0-9a-f]+}} D defined_sym
|
||||
ELF: {{[0-9a-f]+}} T global_func
|
||||
ELF: ? tls_sym
|
@ -61,6 +61,12 @@ namespace {
|
||||
cl::alias UndefinedOnly2("u", cl::desc("Alias for --undefined-only"),
|
||||
cl::aliasopt(UndefinedOnly));
|
||||
|
||||
cl::opt<bool> DynamicSyms("dynamic",
|
||||
cl::desc("Display the dynamic symbols instead "
|
||||
"of normal symbols."));
|
||||
cl::alias DynamicSyms2("D", cl::desc("Alias for --dynamic"),
|
||||
cl::aliasopt(DynamicSyms));
|
||||
|
||||
cl::opt<bool> DefinedOnly("defined-only",
|
||||
cl::desc("Show only defined symbols"));
|
||||
|
||||
@ -277,9 +283,13 @@ static void DumpSymbolNamesFromModule(Module *M) {
|
||||
|
||||
static void DumpSymbolNamesFromObject(ObjectFile *obj) {
|
||||
error_code ec;
|
||||
for (symbol_iterator i = obj->begin_symbols(),
|
||||
e = obj->end_symbols();
|
||||
i != e; i.increment(ec)) {
|
||||
symbol_iterator ibegin = obj->begin_symbols();
|
||||
symbol_iterator iend = obj->end_symbols();
|
||||
if (DynamicSyms) {
|
||||
ibegin = obj->begin_dynamic_symbols();
|
||||
iend = obj->end_dynamic_symbols();
|
||||
}
|
||||
for (symbol_iterator i = ibegin; i != iend; i.increment(ec)) {
|
||||
if (error(ec)) break;
|
||||
bool internal;
|
||||
if (error(i->isInternal(internal))) break;
|
||||
|
Loading…
Reference in New Issue
Block a user