From dfa1896b6b61e708f002b814794890ff308172ee Mon Sep 17 00:00:00 2001 From: "Michael J. Spencer" Date: Tue, 28 Feb 2012 00:40:37 +0000 Subject: [PATCH] [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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@151600 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Object/COFF.h | 2 + include/llvm/Object/ELF.h | 103 ++++++++++++++---- include/llvm/Object/MachO.h | 2 + include/llvm/Object/ObjectFile.h | 3 + lib/Object/COFFObjectFile.cpp | 10 ++ lib/Object/MachOObjectFile.cpp | 9 ++ .../Object/Inputs/shared-object-test.elf-i386 | Bin 0 -> 1792 bytes .../Inputs/shared-object-test.elf-x86-64 | Bin 0 -> 2680 bytes test/Object/Inputs/shared.ll | 31 ++++++ test/Object/nm-shared-object.test | 15 +++ tools/llvm-nm/llvm-nm.cpp | 16 ++- 11 files changed, 168 insertions(+), 23 deletions(-) create mode 100644 test/Object/Inputs/shared-object-test.elf-i386 create mode 100644 test/Object/Inputs/shared-object-test.elf-x86-64 create mode 100644 test/Object/Inputs/shared.ll create mode 100644 test/Object/nm-shared-object.test diff --git a/include/llvm/Object/COFF.h b/include/llvm/Object/COFF.h index 73bde8ef412..71403406909 100644 --- a/include/llvm/Object/COFF.h +++ b/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/include/llvm/Object/ELF.h b/include/llvm/Object/ELF.h index aaeea1d2bf8..2fd10ef6710 100644 --- a/include/llvm/Object/ELF.h +++ b/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/include/llvm/Object/MachO.h b/include/llvm/Object/MachO.h index 7e3a90dab1a..b6e583f6f37 100644 --- a/include/llvm/Object/MachO.h +++ b/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/include/llvm/Object/ObjectFile.h b/include/llvm/Object/ObjectFile.h index 3a4052abdb3..4aa05e234fe 100644 --- a/include/llvm/Object/ObjectFile.h +++ b/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/lib/Object/COFFObjectFile.cpp b/lib/Object/COFFObjectFile.cpp index bdf54314458..a2dad41818e 100644 --- a/lib/Object/COFFObjectFile.cpp +++ b/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/lib/Object/MachOObjectFile.cpp b/lib/Object/MachOObjectFile.cpp index 4fa621ba9e5..b1416eae89d 100644 --- a/lib/Object/MachOObjectFile.cpp +++ b/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/test/Object/Inputs/shared-object-test.elf-i386 b/test/Object/Inputs/shared-object-test.elf-i386 new file mode 100644 index 0000000000000000000000000000000000000000..5129cc40bff421aaa9c410a4f5fa18e83e67fd5e GIT binary patch literal 1792 zcmb7^O-~b16oyY}Q4o|54Kcw4O<2^#G!ii`wFsz5k)W8Un_+0Dlw{hHc1*yS$if8+ z7A*WhCT?7~aN!Sdp+A6~yZSzJdvVm5=tQht>Je3c~7lhM7c092x z*1jb*h5isfKCjG>z_h z=LhqBUn=DVZmtM$Kpnh*ecABJxu}7ks{%3V;1R%|7iy6?0UMtA55alaUOd;g6rhgz zzRCc1WP4#&R-o7uJHQ8hOK2^ut^#2ESysb4MolkmS^X;pSH{yjl z@Lce9yr09rth=E)=4Bn;#nE5tCi*o}sZbYrN1C+|v{ENh)Fo~xcvg`yfxW@uu;9-o z(++g_U5vi?`MjUi{0oTdnC{M1@9XfAbsiv;D8x&oh34F4Ap;ov2odV~g8W-|>RQXAjFO5AIrUud=#Ot^}*g h%a51VgZ1)4Wht<1bIdl)lScVVhjdMoMw#igKLGKbw?+T} literal 0 HcmV?d00001 diff --git a/test/Object/Inputs/shared-object-test.elf-x86-64 b/test/Object/Inputs/shared-object-test.elf-x86-64 new file mode 100644 index 0000000000000000000000000000000000000000..71081ebfd165844fd90b3ab603f1a79f787a734b GIT binary patch literal 2680 zcmcgtPfrt35TCL|s-hG%!~_#C@nT{&5H)fzN)b?#B0(`xF6+|WQj-25?V5lWFCIL4 z^keuDNW6IT;K8F86OQl+>df2uwQnD7Vmvs>+nM*9nfGRA-h1* zd#U>*X9nwFeX6t?jaD=095g73tGmrOGV)HnwH?-j>f2_8l6uErK^%oiNI|gOVIT?H z2?cR8;+2W!55HEK{E3+lm>Yh@e2H@Jo>OkWn42CSD}3T$1i!}PTesUqZp2jZJ3I~@ zT+W{m;(jGR#Dw~NR0Guev+Ct62rZ|KZ%#^5pZ`I)AMRczJfE|kgxlnIl6J~#kZNJ4 zMt*eAl)@OEw8>B6{e=9u7F63|Bj&j&h^WKHZiW1vR^so~*(AlePVT<{I-h1o$u;VL z{Da@ug`vlNLcOlDUUCmT>H~hP{&E&%z#nzGsW|*mZ*bICmoe`nWa0BXB=BzA5e(}@%J<#crWlSB2Tb)=d!-Uj=O?$h4&cmF7((R z|FOZoW`Et_$eT6NkvbsHs_x|<>uj;Y_Q(5$3+cw|&fl=VtcCb`?~oe0_U?Sr@@26{ zc{PlCNGeFIHpv{dv+-kT6ih``USN5G2mTv*kzRt>S?rTOF#CPPNbdfQIy3b+v$#jL z!sCc>KeD(-IQLn6SbrKNoYSoR>Aod;kGm(%SJu8jI5%0m-_Npmzuy3tyyUr`VGf?Y z4SD*dbwIAC*dRA@(skpRQQVE^F5`pxZi(?heRqxVL4Efnl_wtZW9GrKR#pKz38Mn{}^2XF7A* KtffI)J^l}43AZc& literal 0 HcmV?d00001 diff --git a/test/Object/Inputs/shared.ll b/test/Object/Inputs/shared.ll new file mode 100644 index 00000000000..3db0f82d9cd --- /dev/null +++ b/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/test/Object/nm-shared-object.test b/test/Object/nm-shared-object.test new file mode 100644 index 00000000000..b361df53555 --- /dev/null +++ b/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/tools/llvm-nm/llvm-nm.cpp b/tools/llvm-nm/llvm-nm.cpp index 13356f81b80..8688d4af659 100644 --- a/tools/llvm-nm/llvm-nm.cpp +++ b/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; -- 2.34.1