summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/llvm/Object/COFF.h2
-rw-r--r--include/llvm/Object/ELF.h103
-rw-r--r--include/llvm/Object/MachO.h2
-rw-r--r--include/llvm/Object/ObjectFile.h3
-rw-r--r--lib/Object/COFFObjectFile.cpp10
-rw-r--r--lib/Object/MachOObjectFile.cpp9
-rw-r--r--test/Object/Inputs/shared-object-test.elf-i386bin0 -> 1792 bytes
-rw-r--r--test/Object/Inputs/shared-object-test.elf-x86-64bin0 -> 2680 bytes
-rw-r--r--test/Object/Inputs/shared.ll31
-rw-r--r--test/Object/nm-shared-object.test15
-rw-r--r--tools/llvm-nm/llvm-nm.cpp16
11 files changed, 168 insertions, 23 deletions
diff --git a/include/llvm/Object/COFF.h b/include/llvm/Object/COFF.h
index 73bde8ef41..7140340690 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 aaeea1d2bf..2fd10ef671 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<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));
}
@@ -1289,6 +1321,31 @@ symbol_iterator ELFObjectFile<target_endianness, is64Bits>
}
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 {
DataRefImpl ret;
@@ -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;
}
diff --git a/include/llvm/Object/MachO.h b/include/llvm/Object/MachO.h
index 7e3a90dab1..b6e583f6f3 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 3a4052abdb..4aa05e234f 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 bdf5431445..a2dad41818 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 4fa621ba9e..b1416eae89 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 0000000000..5129cc40bf
--- /dev/null
+++ b/test/Object/Inputs/shared-object-test.elf-i386
Binary files differ
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 0000000000..71081ebfd1
--- /dev/null
+++ b/test/Object/Inputs/shared-object-test.elf-x86-64
Binary files differ
diff --git a/test/Object/Inputs/shared.ll b/test/Object/Inputs/shared.ll
new file mode 100644
index 0000000000..3db0f82d9c
--- /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 0000000000..b361df5355
--- /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 13356f81b8..8688d4af65 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<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;