forked from OSchip/llvm-project
[ELF][Writer] Add dynamic string and symbol table.
llvm-svn: 175941
This commit is contained in:
parent
9be2d71512
commit
942dbcc209
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue