[ELF][Writer] Add dynamic string and symbol table.

llvm-svn: 175941
This commit is contained in:
Michael J. Spencer 2013-02-23 01:02:31 +00:00
parent 9be2d71512
commit 942dbcc209
4 changed files with 124 additions and 59 deletions

View File

@ -31,6 +31,7 @@
namespace lld {
namespace elf {
template <class> 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<ELFT>::Kind k = Chunk<ELFT>::K_ELFSection)
: Chunk<ELFT>(name, k, ti), _flags(0), _entSize(0), _type(0), _link(0),
_info(0), _segmentType(SHT_NULL) {}
: Chunk<ELFT>(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<ELFT> *ms) {
_parent = ms;
}
static bool classof(const Chunk<ELFT> *c) {
return c->kind() == Chunk<ELFT>::K_ELFSection ||
c->kind() == Chunk<ELFT>::K_AtomSection;
}
protected:
/// \brief MergedSections this Section is a member of, or nullptr.
MergedSections<ELFT> *_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<ChunkIter> sections() { return _sections; }
// The below functions returns the properties of the MergeSection
@ -460,12 +471,14 @@ MergedSections<ELFT>::appendSection(Chunk<ELFT> *c) {
if (c->align2() > _align2)
_align2 = c->align2();
if (const auto section = dyn_cast<Section<ELFT>>(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<ELFT>::appendSection(Chunk<ELFT> *c) {
template<class ELFT>
class StringTable : public Section<ELFT> {
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 <class ELFT>
StringTable<ELFT>::StringTable(const ELFTargetInfo &ti, const char *str,
int32_t order)
int32_t order, bool dynamic)
: Section<ELFT>(ti, str) {
// the string table has a NULL entry for which
// add an empty string
@ -511,6 +525,10 @@ StringTable<ELFT>::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 <class ELFT> uint64_t StringTable<ELFT>::addString(StringRef symname) {
@ -522,6 +540,8 @@ template <class ELFT> uint64_t StringTable<ELFT>::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<ELFT>::write(ELFWriter *writer,
/// \brief The SymbolTable class represents the symbol table in a ELF file
template<class ELFT>
class SymbolTable : public Section<ELFT> {
public:
typedef typename llvm::object::ELFDataTypeTypedefHelper<ELFT>::Elf_Addr
Elf_Addr;
typedef llvm::object::Elf_Sym_Impl<ELFT> 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<ELFT> *_stringSection;
std::vector<Elf_Sym*> _symbolTable;
std::vector<SymbolEntry> _symbolTable;
};
/// ELF Symbol Table
@ -569,53 +600,53 @@ SymbolTable<ELFT>::SymbolTable(const ELFTargetInfo &ti, const char *str,
int32_t order)
: Section<ELFT>(ti, str) {
this->setOrder(order);
Elf_Sym *symbol = new (_symbolAllocate.Allocate<Elf_Sym>()) 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 <class ELFT>
void SymbolTable<ELFT>::addSymbol(const Atom *atom, int32_t sectionIndex,
uint64_t addr) {
Elf_Sym *symbol = new(_symbolAllocate.Allocate<Elf_Sym>()) 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<const DefinedAtom>(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<ELFT>::addSymbol(const Atom *atom, int32_t sectionIndex,
binding = llvm::ELF::STB_GLOBAL;
} else if (const AbsoluteAtom *aa = dyn_cast<const AbsoluteAtom>(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<ELFT>::addSymbol(const Atom *atom, int32_t sectionIndex,
binding = llvm::ELF::STB_GLOBAL;
break;
}
symbol->st_value = addr;
symbol.st_value = addr;
} else if (isa<const SharedLibraryAtom>(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 <class ELFT> void SymbolTable<ELFT>::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 <class ELFT>
@ -672,12 +713,22 @@ void SymbolTable<ELFT>::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 ELFT> class DynamicSymbolTable : public SymbolTable<ELFT> {
public:
DynamicSymbolTable(const ELFTargetInfo &ti, const char *str, int32_t order)
: SymbolTable<ELFT>(ti, str, order) {
this->_type = SHT_DYNSYM;
this->_flags = SHF_ALLOC;
this->_msize = this->_fsize;
}
};
template <class ELFT> class RelocationTable : public Section<ELFT> {
public:
typedef llvm::object::Elf_Rel_Impl<ELFT, true> Elf_Rela;

View File

@ -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<ELFT>) _dynamicTable;
LLD_UNIQUE_BUMP_PTR(DynamicSymbolTable<ELFT>) _dynamicSymbolTable;
LLD_UNIQUE_BUMP_PTR(StringTable<ELFT>) _dynamicStringTable;
LLD_UNIQUE_BUMP_PTR(InterpSection<ELFT>) _interpSection;
/// @}
CRuntimeFile<ELFT> _runtimeFile;
@ -86,36 +88,32 @@ ExecutableWriter<ELFT>::ExecutableWriter(const ELFTargetInfo &ti)
template <class ELFT>
void ExecutableWriter<ELFT>::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<class ELFT>
void ExecutableWriter<ELFT>::buildSymbolTable () {
template <class ELFT>
void ExecutableWriter<ELFT>::buildStaticSymbolTable(const File &file) {
for (auto sec : _layout->sections())
if (auto section = dyn_cast<AtomSection<ELFT>>(sec))
for (const auto &atom : section->atoms())
_symtab->addSymbol(atom->_atom, section->ordinal(), atom->_virtualAddr);
}
template<class ELFT>
void
ExecutableWriter<ELFT>::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<class ELFT>
void ExecutableWriter<ELFT>::buildAtomToAddressMap () {
template <class ELFT>
void ExecutableWriter<ELFT>::buildDynamicSymbolTable(const File &file) {
for (const auto sla : file.sharedLibrary()) {
_dynamicSymbolTable->addSymbol(sla, ELF::SHN_UNDEF);
}
}
template <class ELFT> void ExecutableWriter<ELFT>::buildAtomToAddressMap() {
for (auto sec : _layout->sections())
if (auto section = dyn_cast<AtomSection<ELFT>>(sec))
for (const auto &atom : section->atoms())
@ -243,6 +241,9 @@ error_code ExecutableWriter<ELFT>::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<ELFT>::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<ELFT>::createDefaultSections() {
if (_targetInfo.isDynamic()) {
_dynamicTable.reset(new (_alloc) DynamicTable<ELFT>(
_targetInfo, ".dynamic", DefaultLayout<ELFT>::ORDER_DYNAMIC));
_dynamicStringTable.reset(new (_alloc) StringTable<ELFT>(
_targetInfo, ".dynstr", DefaultLayout<ELFT>::ORDER_DYNAMIC_STRINGS,
true));
_dynamicSymbolTable.reset(new (_alloc) DynamicSymbolTable<ELFT>(
_targetInfo, ".dynsym", DefaultLayout<ELFT>::ORDER_DYNAMIC_SYMBOLS));
_interpSection.reset(new (_alloc) InterpSection<ELFT>(
_targetInfo, ".interp", DefaultLayout<ELFT>::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

View File

@ -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

View File

@ -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