From 942dbcc20914e0b465fbc1bccb85151e83e6ca3a Mon Sep 17 00:00:00 2001 From: "Michael J. Spencer" Date: Sat, 23 Feb 2013 01:02:31 +0000 Subject: [PATCH] [ELF][Writer] Add dynamic string and symbol table. llvm-svn: 175941 --- lld/lib/ReaderWriter/ELF/SectionChunks.h | 123 ++++++++++++++++++++++--------- lld/lib/ReaderWriter/ELF/Writer.cpp | 50 +++++++------ lld/test/elf/dynamic-symbols.test | 8 ++ lld/test/elf/sections.objtxt | 2 +- 4 files changed, 124 insertions(+), 59 deletions(-) create mode 100644 lld/test/elf/dynamic-symbols.test diff --git a/lld/lib/ReaderWriter/ELF/SectionChunks.h b/lld/lib/ReaderWriter/ELF/SectionChunks.h index 8b4c87b..b5ca854 100644 --- a/lld/lib/ReaderWriter/ELF/SectionChunks.h +++ b/lld/lib/ReaderWriter/ELF/SectionChunks.h @@ -31,6 +31,7 @@ namespace lld { namespace elf { +template class MergedSections; using namespace llvm::ELF; /// \brief An ELF section. @@ -39,8 +40,8 @@ public: /// \param type the ELF SHT_* type of the section. Section(const ELFTargetInfo &ti, StringRef name, typename Chunk::Kind k = Chunk::K_ELFSection) - : Chunk(name, k, ti), _flags(0), _entSize(0), _type(0), _link(0), - _info(0), _segmentType(SHT_NULL) {} + : Chunk(name, k, ti), _parent(nullptr), _flags(0), _entSize(0), + _type(0), _link(0), _info(0), _segmentType(SHT_NULL) {} /// \brief Modify the section contents before assigning virtual addresses // or assigning file offsets @@ -82,12 +83,18 @@ public: this->_segmentType = segmentType; } + void setMergedSection(MergedSections *ms) { + _parent = ms; + } + static bool classof(const Chunk *c) { return c->kind() == Chunk::K_ELFSection || c->kind() == Chunk::K_AtomSection; } protected: + /// \brief MergedSections this Section is a member of, or nullptr. + MergedSections *_parent; /// \brief ELF SHF_* flags. uint64_t _flags; /// \brief The size of each entity. @@ -386,6 +393,10 @@ public: _virtualAddr = addr; } + void setLink(uint64_t link) { _link = link; } + + void setInfo(uint64_t info) { _shInfo = info; } + inline range sections() { return _sections; } // The below functions returns the properties of the MergeSection @@ -460,12 +471,14 @@ MergedSections::appendSection(Chunk *c) { if (c->align2() > _align2) _align2 = c->align2(); if (const auto section = dyn_cast>(c)) { + assert(!_link && "Section already has a link!"); _link = section->getLink(); _shInfo = section->getInfo(); _entSize = section->getEntSize(); _type = section->getType(); if (_flags < section->getFlags()) _flags = section->getFlags(); + section->setMergedSection(this); } _kind = c->kind(); _sections.push_back(c); @@ -475,7 +488,8 @@ MergedSections::appendSection(Chunk *c) { template class StringTable : public Section { public: - StringTable(const ELFTargetInfo &, const char *str, int32_t order); + StringTable(const ELFTargetInfo &, const char *str, int32_t order, + bool dynamic = false); uint64_t addString(StringRef symname); @@ -502,7 +516,7 @@ private: template StringTable::StringTable(const ELFTargetInfo &ti, const char *str, - int32_t order) + int32_t order, bool dynamic) : Section(ti, str) { // the string table has a NULL entry for which // add an empty string @@ -511,6 +525,10 @@ StringTable::StringTable(const ELFTargetInfo &ti, const char *str, this->_align2 = 1; this->setOrder(order); this->_type = SHT_STRTAB; + if (dynamic) { + this->_flags = SHF_ALLOC; + this->_msize = this->_fsize; + } } template uint64_t StringTable::addString(StringRef symname) { @@ -522,6 +540,8 @@ template uint64_t StringTable::addString(StringRef symname) { _strings.push_back(symname); uint64_t offset = this->_fsize; this->_fsize += symname.size() + 1; + if (this->_flags & SHF_ALLOC) + this->_msize = this->_fsize; _stringMap[symname] = offset; return offset; } @@ -544,9 +564,20 @@ void StringTable::write(ELFWriter *writer, /// \brief The SymbolTable class represents the symbol table in a ELF file template class SymbolTable : public Section { -public: + typedef typename llvm::object::ELFDataTypeTypedefHelper::Elf_Addr + Elf_Addr; typedef llvm::object::Elf_Sym_Impl Elf_Sym; + struct SymbolEntry { + SymbolEntry(const Atom *a, const Elf_Sym &sym) : _atom(a), _symbol(sym) {} + + SymbolEntry() : _atom(nullptr) {} + + const Atom *_atom; + Elf_Sym _symbol; + }; + +public: SymbolTable(const ELFTargetInfo &ti, const char *str, int32_t order); void addSymbol(const Atom *atom, int32_t sectionIndex, uint64_t addr = 0); @@ -560,7 +591,7 @@ public: private: llvm::BumpPtrAllocator _symbolAllocate; StringTable *_stringSection; - std::vector _symbolTable; + std::vector _symbolTable; }; /// ELF Symbol Table @@ -569,53 +600,53 @@ SymbolTable::SymbolTable(const ELFTargetInfo &ti, const char *str, int32_t order) : Section(ti, str) { this->setOrder(order); - Elf_Sym *symbol = new (_symbolAllocate.Allocate()) Elf_Sym; - memset((void *)symbol, 0, sizeof(Elf_Sym)); - _symbolTable.push_back(symbol); + Elf_Sym symbol; + std::memset(&symbol, 0, sizeof(Elf_Sym)); + _symbolTable.push_back(SymbolEntry(nullptr, symbol)); this->_entSize = sizeof(Elf_Sym); this->_fsize = sizeof(Elf_Sym); - this->_align2 = sizeof(void *); + this->_align2 = sizeof(Elf_Addr); this->_type = SHT_SYMTAB; } template void SymbolTable::addSymbol(const Atom *atom, int32_t sectionIndex, uint64_t addr) { - Elf_Sym *symbol = new(_symbolAllocate.Allocate()) Elf_Sym; + Elf_Sym symbol; unsigned char binding = 0, type = 0; - symbol->st_name = _stringSection->addString(atom->name()); - symbol->st_size = 0; - symbol->st_shndx = sectionIndex; - symbol->st_value = 0; - symbol->st_other = llvm::ELF::STV_DEFAULT; + symbol.st_name = _stringSection->addString(atom->name()); + symbol.st_size = 0; + symbol.st_shndx = sectionIndex; + symbol.st_value = 0; + symbol.st_other = llvm::ELF::STV_DEFAULT; if (const DefinedAtom *da = dyn_cast(atom)){ - symbol->st_size = da->size(); + symbol.st_size = da->size(); DefinedAtom::ContentType ct; switch (ct = da->contentType()){ case DefinedAtom::typeCode: case DefinedAtom::typeStub: - symbol->st_value = addr; + symbol.st_value = addr; type = llvm::ELF::STT_FUNC; break; case DefinedAtom::typeResolver: - symbol->st_value = addr; + symbol.st_value = addr; type = llvm::ELF::STT_GNU_IFUNC; break; case DefinedAtom::typeDataFast: case DefinedAtom::typeData: case DefinedAtom::typeConstant: case DefinedAtom::typeGOT: - symbol->st_value = addr; + symbol.st_value = addr; type = llvm::ELF::STT_OBJECT; break; case DefinedAtom::typeZeroFill: type = llvm::ELF::STT_OBJECT; - symbol->st_value = addr; + symbol.st_value = addr; break; case DefinedAtom::typeTLVInitialData: case DefinedAtom::typeTLVInitialZeroFill: type = llvm::ELF::STT_TLS; - symbol->st_value = addr; + symbol.st_value = addr; break; default: type = llvm::ELF::STT_NOTYPE; @@ -626,10 +657,10 @@ void SymbolTable::addSymbol(const Atom *atom, int32_t sectionIndex, binding = llvm::ELF::STB_GLOBAL; } else if (const AbsoluteAtom *aa = dyn_cast(atom)){ type = llvm::ELF::STT_OBJECT; - symbol->st_shndx = llvm::ELF::SHN_ABS; + symbol.st_shndx = llvm::ELF::SHN_ABS; switch (aa->scope()) { case AbsoluteAtom::scopeLinkageUnit: - symbol->st_other = llvm::ELF::STV_HIDDEN; + symbol.st_other = llvm::ELF::STV_HIDDEN; binding = llvm::ELF::STB_LOCAL; break; case AbsoluteAtom::scopeTranslationUnit: @@ -639,32 +670,42 @@ void SymbolTable::addSymbol(const Atom *atom, int32_t sectionIndex, binding = llvm::ELF::STB_GLOBAL; break; } - symbol->st_value = addr; + symbol.st_value = addr; + } else if (isa(atom)) { + type = llvm::ELF::STT_FUNC; + symbol.st_shndx = llvm::ELF::SHN_UNDEF; + binding = llvm::ELF::STB_GLOBAL; } else { - symbol->st_value = 0; - type = llvm::ELF::STT_NOTYPE; - binding = llvm::ELF::STB_WEAK; + symbol.st_value = 0; + type = llvm::ELF::STT_NOTYPE; + binding = llvm::ELF::STB_WEAK; } - symbol->setBindingAndType(binding, type); - _symbolTable.push_back(symbol); + symbol.setBindingAndType(binding, type); + _symbolTable.push_back(SymbolEntry(atom, symbol)); this->_fsize += sizeof(Elf_Sym); + if (this->_flags & SHF_ALLOC) + this->_msize = this->_fsize; } template void SymbolTable::finalize() { // sh_info should be one greater than last symbol with STB_LOCAL binding // we sort the symbol table to keep all local symbols at the beginning std::stable_sort(_symbolTable.begin(), _symbolTable.end(), - [](const Elf_Sym *A, const Elf_Sym *B) { - return A->getBinding() < B->getBinding(); + [](const SymbolEntry & A, const SymbolEntry & B) { + return A._symbol.getBinding() < B._symbol.getBinding(); }); uint16_t shInfo = 0; - for (auto i : _symbolTable) { - if (i->getBinding() != llvm::ELF::STB_LOCAL) + for (const auto &i : _symbolTable) { + if (i._symbol.getBinding() != llvm::ELF::STB_LOCAL) break; shInfo++; } this->_info = shInfo; this->_link = _stringSection->ordinal(); + if (this->_parent) { + this->_parent->setInfo(this->_info); + this->_parent->setLink(this->_link); + } } template @@ -672,12 +713,22 @@ void SymbolTable::write(ELFWriter *writer, llvm::FileOutputBuffer &buffer) { uint8_t *chunkBuffer = buffer.getBufferStart(); uint8_t *dest = chunkBuffer + this->fileOffset(); - for (auto sti : _symbolTable) { - memcpy(dest, sti, sizeof(Elf_Sym)); + for (const auto &sti : _symbolTable) { + memcpy(dest, &sti._symbol, sizeof(Elf_Sym)); dest += sizeof(Elf_Sym); } } +template class DynamicSymbolTable : public SymbolTable { +public: + DynamicSymbolTable(const ELFTargetInfo &ti, const char *str, int32_t order) + : SymbolTable(ti, str, order) { + this->_type = SHT_DYNSYM; + this->_flags = SHF_ALLOC; + this->_msize = this->_fsize; + } +}; + template class RelocationTable : public Section { public: typedef llvm::object::Elf_Rel_Impl Elf_Rela; diff --git a/lld/lib/ReaderWriter/ELF/Writer.cpp b/lld/lib/ReaderWriter/ELF/Writer.cpp index 4272eb8..5e2bb1e 100644 --- a/lld/lib/ReaderWriter/ELF/Writer.cpp +++ b/lld/lib/ReaderWriter/ELF/Writer.cpp @@ -38,10 +38,10 @@ private: void buildChunks(const File &file); virtual error_code writeFile(const File &File, StringRef path); void buildAtomToAddressMap(); - void buildSymbolTable (); + void buildStaticSymbolTable(const File &file); + void buildDynamicSymbolTable(const File &file); void buildSectionHeaderTable(); void assignSectionsWithNoSegments(); - void addAbsoluteUndefinedSymbols(const File &File); void addDefaultAtoms(); void addFiles(InputFiles&); void finalizeDefaultAtomValues(); @@ -69,6 +69,8 @@ private: /// \name Dynamic sections. /// @{ LLD_UNIQUE_BUMP_PTR(DynamicTable) _dynamicTable; + LLD_UNIQUE_BUMP_PTR(DynamicSymbolTable) _dynamicSymbolTable; + LLD_UNIQUE_BUMP_PTR(StringTable) _dynamicStringTable; LLD_UNIQUE_BUMP_PTR(InterpSection) _interpSection; /// @} CRuntimeFile _runtimeFile; @@ -86,36 +88,32 @@ ExecutableWriter::ExecutableWriter(const ELFTargetInfo &ti) template void ExecutableWriter::buildChunks(const File &file) { - for (const DefinedAtom *definedAtom : file.defined() ) { + for (const DefinedAtom *definedAtom : file.defined()) _layout->addAtom(definedAtom); - } - /// Add all the absolute atoms to the layout - for (const AbsoluteAtom *absoluteAtom : file.absolute()) { + for (const AbsoluteAtom *absoluteAtom : file.absolute()) _layout->addAtom(absoluteAtom); - } } -template -void ExecutableWriter::buildSymbolTable () { +template +void ExecutableWriter::buildStaticSymbolTable(const File &file) { for (auto sec : _layout->sections()) if (auto section = dyn_cast>(sec)) for (const auto &atom : section->atoms()) _symtab->addSymbol(atom->_atom, section->ordinal(), atom->_virtualAddr); -} - -template -void -ExecutableWriter::addAbsoluteUndefinedSymbols(const File &file) { - // add all the absolute symbols that the layout contains to the output symbol - // table for (auto &atom : _layout->absoluteAtoms()) _symtab->addSymbol(atom->_atom, ELF::SHN_ABS, atom->_virtualAddr); for (const UndefinedAtom *a : file.undefined()) _symtab->addSymbol(a, ELF::SHN_UNDEF); } -template -void ExecutableWriter::buildAtomToAddressMap () { +template +void ExecutableWriter::buildDynamicSymbolTable(const File &file) { + for (const auto sla : file.sharedLibrary()) { + _dynamicSymbolTable->addSymbol(sla, ELF::SHN_UNDEF); + } +} + +template void ExecutableWriter::buildAtomToAddressMap() { for (auto sec : _layout->sections()) if (auto section = dyn_cast>(sec)) for (const auto &atom : section->atoms()) @@ -243,6 +241,9 @@ error_code ExecutableWriter::writeFile(const File &file, StringRef path) { // section string table createDefaultSections(); + if (_targetInfo.isDynamic()) + buildDynamicSymbolTable(file); + // Set the Layout _layout->assignSectionsToSegments(); _layout->assignFileOffsets(); @@ -255,10 +256,7 @@ error_code ExecutableWriter::writeFile(const File &file, StringRef path) { buildAtomToAddressMap(); // Create symbol table and section string table - buildSymbolTable(); - - // add other symbols - addAbsoluteUndefinedSymbols(file); + buildStaticSymbolTable(file); // Finalize the layout by calling the finalize() functions _layout->finalize(); @@ -342,11 +340,19 @@ void ExecutableWriter::createDefaultSections() { if (_targetInfo.isDynamic()) { _dynamicTable.reset(new (_alloc) DynamicTable( _targetInfo, ".dynamic", DefaultLayout::ORDER_DYNAMIC)); + _dynamicStringTable.reset(new (_alloc) StringTable( + _targetInfo, ".dynstr", DefaultLayout::ORDER_DYNAMIC_STRINGS, + true)); + _dynamicSymbolTable.reset(new (_alloc) DynamicSymbolTable( + _targetInfo, ".dynsym", DefaultLayout::ORDER_DYNAMIC_SYMBOLS)); _interpSection.reset(new (_alloc) InterpSection( _targetInfo, ".interp", DefaultLayout::ORDER_INTERP, _targetInfo.getInterpreter())); _layout->addSection(_dynamicTable.get()); + _layout->addSection(_dynamicStringTable.get()); + _layout->addSection(_dynamicSymbolTable.get()); _layout->addSection(_interpSection.get()); + _dynamicSymbolTable->setStringSection(_dynamicStringTable.get()); } // give a chance for the target to add sections diff --git a/lld/test/elf/dynamic-symbols.test b/lld/test/elf/dynamic-symbols.test new file mode 100644 index 0000000..1d446ae --- /dev/null +++ b/lld/test/elf/dynamic-symbols.test @@ -0,0 +1,8 @@ +RUN: lld -core -target x86_64-linux %p/Inputs/use-shared.x86-64 \ +RUN: %p/Inputs/shared.so-x86-64 -output=%t -entry=main \ +RUN: -output-type=dynamic +RUN: llvm-readobj %t | FileCheck %s + +CHECK: Dynamic Symbols: +CHECK: foo FUNC {{[0-9a-f]+}} 0 {{[0-9a-f]+}} undef,global +CHECK: Total: 1 diff --git a/lld/test/elf/sections.objtxt b/lld/test/elf/sections.objtxt index 0a5ce12..250f6ef 100644 --- a/lld/test/elf/sections.objtxt +++ b/lld/test/elf/sections.objtxt @@ -31,5 +31,5 @@ ED: 'sh_link', 0x00000000 ED: 'sh_addralign', 0x00000001 ED: Section 7 ED: 'sh_link', 0x00000008 -ED: 'sh_addralign', 0x00000008 +ED: 'sh_addralign', 0x00000004 ED: 'sh_entsize', 0x00000010 -- 2.7.4