diff --git a/llvm/include/llvm/Object/COFF.h b/llvm/include/llvm/Object/COFF.h index 73bde8ef4125..714034069095 100644 --- a/llvm/include/llvm/Object/COFF.h +++ b/llvm/include/llvm/Object/COFF.h @@ -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; diff --git a/llvm/include/llvm/Object/ELF.h b/llvm/include/llvm/Object/ELF.h index aaeea1d2bf85..2fd10ef6710d 100644 --- a/llvm/include/llvm/Object/ELF.h +++ b/llvm/include/llvm/Object/ELF.h @@ -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 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 // 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::max(); Symb.d.b = std::numeric_limits::max(); } @@ -444,7 +454,7 @@ error_code ELFObjectFile StringRef &Result) const { validateSymbol(Symb); const Elf_Sym *symb = getSymbol(Symb); - return getSymbolName(symb, Result); + return getSymbolName(SymbolTableSections[Symb.d.b], symb, Result); } template @@ -1128,7 +1138,7 @@ error_code ELFObjectFile } const Elf_Sym *symb = getEntry(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 return object_error::success; } +// Verify that the last byte in the string table in a null. +template +void ELFObjectFile + ::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 ELFObjectFile::ELFObjectFile(MemoryBuffer *Object , error_code &ec) @@ -1163,7 +1183,8 @@ ELFObjectFile::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::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::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::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::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 ::begin_symbols() const { DataRefImpl SymbolData; memset(&SymbolData, 0, sizeof(SymbolData)); - if (SymbolTableSections.size() == 0) { + if (SymbolTableSections.size() <= 1) { SymbolData.d.a = std::numeric_limits::max(); SymbolData.d.b = std::numeric_limits::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 return symbol_iterator(SymbolRef(SymbolData, this)); } +template +symbol_iterator ELFObjectFile + ::begin_dynamic_symbols() const { + DataRefImpl SymbolData; + memset(&SymbolData, 0, sizeof(SymbolData)); + if (SymbolTableSections[0] == NULL) { + SymbolData.d.a = std::numeric_limits::max(); + SymbolData.d.b = std::numeric_limits::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 +symbol_iterator ELFObjectFile + ::end_dynamic_symbols() const { + DataRefImpl SymbolData; + memset(&SymbolData, 0, sizeof(SymbolData)); + SymbolData.d.a = std::numeric_limits::max(); + SymbolData.d.b = std::numeric_limits::max(); + return symbol_iterator(SymbolRef(SymbolData, this)); +} + template section_iterator ELFObjectFile ::begin_sections() const { @@ -1461,7 +1518,8 @@ const char *ELFObjectFile template error_code ELFObjectFile - ::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 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; } diff --git a/llvm/include/llvm/Object/MachO.h b/llvm/include/llvm/Object/MachO.h index 7e3a90dab1a8..b6e583f6f37d 100644 --- a/llvm/include/llvm/Object/MachO.h +++ b/llvm/include/llvm/Object/MachO.h @@ -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; diff --git a/llvm/include/llvm/Object/ObjectFile.h b/llvm/include/llvm/Object/ObjectFile.h index 3a4052abdb32..4aa05e234fef 100644 --- a/llvm/include/llvm/Object/ObjectFile.h +++ b/llvm/include/llvm/Object/ObjectFile.h @@ -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; diff --git a/llvm/lib/Object/COFFObjectFile.cpp b/llvm/lib/Object/COFFObjectFile.cpp index bdf54314458b..a2dad41818e1 100644 --- a/llvm/lib/Object/COFFObjectFile.cpp +++ b/llvm/lib/Object/COFFObjectFile.cpp @@ -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)); diff --git a/llvm/lib/Object/MachOObjectFile.cpp b/llvm/lib/Object/MachOObjectFile.cpp index 4fa621ba9e5a..b1416eae89de 100644 --- a/llvm/lib/Object/MachOObjectFile.cpp +++ b/llvm/lib/Object/MachOObjectFile.cpp @@ -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 ----------------------------------------------------------===*/ diff --git a/llvm/test/Object/Inputs/shared-object-test.elf-i386 b/llvm/test/Object/Inputs/shared-object-test.elf-i386 new file mode 100644 index 000000000000..5129cc40bff4 Binary files /dev/null and b/llvm/test/Object/Inputs/shared-object-test.elf-i386 differ diff --git a/llvm/test/Object/Inputs/shared-object-test.elf-x86-64 b/llvm/test/Object/Inputs/shared-object-test.elf-x86-64 new file mode 100644 index 000000000000..71081ebfd165 Binary files /dev/null and b/llvm/test/Object/Inputs/shared-object-test.elf-x86-64 differ diff --git a/llvm/test/Object/Inputs/shared.ll b/llvm/test/Object/Inputs/shared.ll new file mode 100644 index 000000000000..3db0f82d9cd5 --- /dev/null +++ b/llvm/test/Object/Inputs/shared.ll @@ -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 +} diff --git a/llvm/test/Object/nm-shared-object.test b/llvm/test/Object/nm-shared-object.test new file mode 100644 index 000000000000..b361df535553 --- /dev/null +++ b/llvm/test/Object/nm-shared-object.test @@ -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 diff --git a/llvm/tools/llvm-nm/llvm-nm.cpp b/llvm/tools/llvm-nm/llvm-nm.cpp index 13356f81b80e..8688d4af6597 100644 --- a/llvm/tools/llvm-nm/llvm-nm.cpp +++ b/llvm/tools/llvm-nm/llvm-nm.cpp @@ -61,6 +61,12 @@ namespace { cl::alias UndefinedOnly2("u", cl::desc("Alias for --undefined-only"), cl::aliasopt(UndefinedOnly)); + cl::opt 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 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;