From: Hemant Kulkarni Date: Mon, 1 Oct 2012 23:53:20 +0000 (+0000) Subject: Emit symbol tables. X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=08e410293fca04939caf631d738e0d7d62f4ae49;p=platform%2Fupstream%2Fllvm.git Emit symbol tables. Reorganize to derive all sections from SectionChunk. Construct section table header from SectionChunk. llvm-svn: 164981 --- diff --git a/lld/include/lld/ReaderWriter/WriterELF.h b/lld/include/lld/ReaderWriter/WriterELF.h index 1185e8a..da52762 100644 --- a/lld/include/lld/ReaderWriter/WriterELF.h +++ b/lld/include/lld/ReaderWriter/WriterELF.h @@ -31,6 +31,7 @@ public: : _is64Bit(false) , _endianness(llvm::support::little) , _type(llvm::ELF::ET_EXEC) + , _pointerWidth(4) , _machine(llvm::ELF::EM_386) {} @@ -43,16 +44,19 @@ public: WriterOptionsELF(const bool Is64Bit, const llvm::support::endianness endian, const uint16_t Type, - const uint16_t Machine) + const uint16_t Machine, + uint64_t pointerWidth = 4) : _is64Bit(Is64Bit) , _endianness(endian) , _type(Type) + , _pointerWidth(pointerWidth) , _machine(Machine) {} bool is64Bit() const { return _is64Bit; } llvm::support::endianness endianness() const { return _endianness; } uint16_t type() const { return _type; } uint16_t machine() const { return _machine; } + uint16_t pointerWidth() const { return _pointerWidth; } /// \brief Get the entry point if type() is ET_EXEC. Empty otherwise. StringRef entryPoint() const; @@ -61,6 +65,7 @@ protected: bool _is64Bit; llvm::support::endianness _endianness; uint16_t _type; + uint16_t _pointerWidth; uint16_t _machine; }; diff --git a/lld/lib/ReaderWriter/ELF/WriterELF.cpp b/lld/lib/ReaderWriter/ELF/WriterELF.cpp index 139f5bd..c81ddaa 100644 --- a/lld/lib/ReaderWriter/ELF/WriterELF.cpp +++ b/lld/lib/ReaderWriter/ELF/WriterELF.cpp @@ -63,51 +63,86 @@ public: uint64_t fileOffset() const; uint64_t align2() const; static uint64_t alignTo(uint64_t value, uint8_t align2); + uint64_t ordinal() const { return _ordinal;} + void setOrdinal(uint64_t newVal) { _ordinal = newVal;} protected: Chunk(); - uint64_t _size; uint64_t _address; uint64_t _fileOffset; uint64_t _align2; + uint64_t _ordinal; }; +template +static void swapChunkPositions(Chunk&a, + Chunk&b) { + uint64_t tempOrdinal; + if (a.ordinal() == b.ordinal()) return; + tempOrdinal = a.ordinal(); + a.setOrdinal(b.ordinal()); + b.setOrdinal(tempOrdinal); +} + /// Pair of atom and offset in section. typedef std::tuple AtomInfo; -/// \brief A Section represents a set of Atoms assigned to a specific ELF -/// Section. +/// \brief A SectionChunk represents ELF sections template class SectionChunk : public Chunk { public: - SectionChunk(DefinedAtom::ContentType, - StringRef sectionName, - const WriterOptionsELF &options, + virtual StringRef segmentName() const { return _segmentName; } + virtual bool occupiesNoDiskSpace(); + virtual const char *info(); + StringRef sectionName() { return _sectionName; } + uint64_t shStrtableOffset(){ return _offsetInStringTable; } + void setShStrtableOffset (uint64_t val) { + _offsetInStringTable = val; } + uint32_t flags() { return _flags; } + uint32_t type() { return _type; } + uint64_t link() { return _link; } + void link(uint64_t val) { _link = val; } + uint16_t shinfo() { return _shinfo; } + bool isLoadable() { return _isLoadable; } + void isLoadable(uint64_t val) { _isLoadable = val; } + uint64_t entsize() { return _entsize; } + SectionChunk(StringRef secName, StringRef segName, bool loadable, + uint64_t flags , uint64_t link, uint64_t info , + uint64_t type, uint64_t entsz, const WriterOptionsELF &op, ELFWriter &writer); - virtual StringRef segmentName() const; - virtual bool occupiesNoDiskSpace(); - virtual void write(uint8_t *fileBuffer); - virtual const char *info(); - StringRef sectionName(); - uint32_t flags() const; - uint32_t type() const; - uint32_t permissions(); - void appendAtom(const DefinedAtom*); - const ArrayRef atoms() const; - -private: +protected: + bool _isLoadable; + uint64_t _link; + uint64_t _shinfo; + uint16_t _entsize; StringRef _segmentName; StringRef _sectionName; const WriterOptionsELF &_options; ELFWriter &_writer; - uint32_t _flags; - uint32_t _type; - uint32_t _permissions; - std::vector _atoms; + uint64_t _flags; + uint64_t _type; + uint64_t _offsetInStringTable; }; +/// \brief A StockSectionChunk is a section created by linker with all +/// attributes concluded from the defined atom contained within. +template +class StockSectionChunk : public SectionChunk { +public: + virtual StringRef segmentName() { return this->_segmentName; } + void appendAtom(const DefinedAtom*); + virtual void write(uint8_t *filebuffer); + const ArrayRef atoms() const; + StockSectionChunk(StringRef sectionName, bool loadable, + DefinedAtom::ContentType type, + const WriterOptionsELF &options, + ELFWriter &writer); +private: + std::vector _atoms; +}; + /// \brief An ELFHeaderChunk represents the Elf[32/64]_Ehdr structure at the /// start of an ELF executable file. template @@ -133,8 +168,7 @@ public: void e_shentsize(uint16_t shentsize) { _eh.e_shentsize = shentsize; } void e_shnum(uint16_t shnum) { _eh.e_shnum = shnum; } void e_shstrndx(uint16_t shstrndx) { _eh.e_shstrndx = shstrndx; } - - uint64_t size() { return sizeof (Elf_Ehdr); } + uint64_t size() { return sizeof (Elf_Ehdr); } virtual StringRef segmentName() const; virtual void write(uint8_t *fileBuffer); @@ -144,12 +178,9 @@ private: Elf_Ehdr _eh; }; - /// \brief An ELFSectionHeaderChunk represents the Elf[32/64]_Shdr structure /// that is placed right after the ELFHeader. /// -/// When this is finished it will need to update the header with the size and -/// number of section headers, e_shentsize, e_shnum. template class ELFSectionHeaderChunk : public Chunk { public: @@ -157,20 +188,17 @@ public: typedef object::Elf_Shdr_Impl Elf_Shdr; ELFSectionHeaderChunk(const WriterOptionsELF &Options, ELFWriter&); - + void createHeaders(); virtual StringRef segmentName() const; virtual void write(uint8_t *filebuffer); virtual const char *info(); void computeSize(const lld::File &file); uint16_t count(); uint16_t size(); - const ArrayRef sectionInfo() { return _sectionInfo; } - bool is64Bit() { return _options.is64Bit(); } - private: const WriterOptionsELF &_options; ELFWriter &_writer; @@ -184,32 +212,44 @@ private: /// null character. We might need more than one such chunks shstrtab for setting /// e_shstrndx in ELHHeaderChunk and strtab for use with symtab template -class ELFStringSectionChunk : public Chunk { +class ELFStringSectionChunk : public SectionChunk { public: - LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits) ELFStringSectionChunk(const WriterOptionsELF &Options, ELFWriter &writer, StringRef secName); - - uint64_t addString(StringRef symName); - - virtual StringRef segmentName() const; + virtual StringRef segmentName() const { return this->_segmentName; } + uint64_t addString(StringRef symName); + const char *info(); virtual void write(uint8_t *filebuffer); - virtual const char *info(); - StringRef sectionName(); +private: + std::vector _stringSection; +}; +/// \brief Represents the symtab section +/// +/// ELFSymbolTableChunk represents the Symbol table as per ELF ABI +/// This is a table with Elf[32/64]_Sym entries in it. +template +class ELFSymbolTableChunk : public SectionChunk { +public: + typedef object::Elf_Sym_Impl Elf_Sym; + ELFSymbolTableChunk(const WriterOptionsELF &options, + ELFWriter &writer, + StringRef secName); + virtual StringRef segmentName() const { return this->_segmentName; } + void addSymbol(const Atom *a, uint16_t shndx); + void addSymbol(Elf_Sym *x); + const char *info(); + void setAttributes(); + virtual void write(uint8_t *fileBuffer); private: - StringRef _segName; - std::vector _StringSection; - StringRef _sectionName; - ELFWriter &_writer; - const WriterOptionsELF &_options; - + std::vector _symbolTable; + ELFStringSectionChunk *_stringSection; + llvm::BumpPtrAllocator _symbolAllocate; }; - /// An ELFProgramHeaderChunk represents the Elf[32/64]_Phdr structure near /// the start of an ELF executable file. Will need to update ELFHeader's /// e_phentsize/e_phnum when done. @@ -221,17 +261,14 @@ public: const WriterOptionsELF &options, const File &file); - virtual StringRef segmentName() const; virtual void write(uint8_t *filebuffer); virtual const char *info(); private: // TODO: Replace this with correct ELF::* type method -//uint32_t filetype(WriterOptionsELF::OutputKind kind); }; - //===----------------------------------------------------------------------===// // Chunk //===----------------------------------------------------------------------===// @@ -239,6 +276,9 @@ private: template Chunk::Chunk() : _size(0), _address(0), _fileOffset(0), _align2(0) { + // 0 and 1 are reserved. 0 for ELF header and 1 for Sectiontable header. + static uint64_t orderNumber = 0; + _ordinal = orderNumber++; } template @@ -308,41 +348,21 @@ void Chunk:: template SectionChunk:: - SectionChunk(DefinedAtom::ContentType type, - StringRef sectionName, - const WriterOptionsELF &options, - ELFWriter &writer) - : _options(options) - , _writer(writer) { - switch(type) { - case DefinedAtom::typeCode: - _segmentName = "PT_LOAD"; - _sectionName = sectionName; - _flags = ELF::SHF_ALLOC | ELF::SHF_EXECINSTR; - _type = ELF::SHT_PROGBITS; - break; - case DefinedAtom::typeData: - _segmentName = "PT_LOAD"; - _sectionName = sectionName; - _flags = ELF::SHF_ALLOC | ELF::SHF_WRITE; - _type = ELF::SHT_PROGBITS; - break; - case DefinedAtom::typeZeroFill: - _segmentName = "PT_LOAD"; - _sectionName = sectionName; - _flags = ELF::SHF_ALLOC | ELF::SHF_WRITE; - _type = ELF::SHT_NOBITS; - break; - case DefinedAtom::typeConstant: - _segmentName = "PT_LOAD"; - _sectionName = sectionName; - _flags = ELF::SHF_ALLOC; - _type = ELF::SHT_PROGBITS; - break; - default: - llvm_unreachable("Unhandled content type for section!"); - } -} + SectionChunk(StringRef secName, StringRef segName, bool loadable, + uint64_t flags , uint64_t link, uint64_t info , uint64_t type, + uint64_t entsz, const WriterOptionsELF &op, + ELFWriter &writer) + : _isLoadable(loadable) + , _link(link) + , _shinfo(info) + , _entsize(entsz) + , _segmentName(segName) + , _sectionName(secName) + , _options(op) + , _writer(writer) + , _flags(flags) + , _type(type) + , _offsetInStringTable(0) {} template bool SectionChunk::occupiesNoDiskSpace() { @@ -350,45 +370,51 @@ bool SectionChunk::occupiesNoDiskSpace() { } template -StringRef SectionChunk::segmentName() const { - return _segmentName; -} - -template -StringRef SectionChunk::sectionName() { - return _sectionName; -} - -template -uint32_t SectionChunk::flags() const { - return _flags; -} - -template -uint32_t SectionChunk::type() const { - return _type; +const char *SectionChunk::info() { + return _sectionName.data(); } -template -uint32_t SectionChunk::permissions() { - return _permissions; -} +//===----------------------------------------------------------------------===// +// StockSectionChunk +//===----------------------------------------------------------------------===// template -const char *SectionChunk::info() { - return _sectionName.data(); +StockSectionChunk:: + StockSectionChunk(StringRef secName, bool loadable, + DefinedAtom::ContentType type, + const WriterOptionsELF &options, + ELFWriter &writer) + : SectionChunk(secName, "PT_NULL", + loadable, 0lu, 0lu, 0u, 0lu, 0lu, + options, writer) { + this->_segmentName = this->_isLoadable ? "PT_LOAD" : "PT_NULL" ; + switch(type) { + case DefinedAtom::typeCode: + this->_type = ELF::SHT_PROGBITS; + break; + case DefinedAtom::typeData: + this->_type = ELF::SHT_PROGBITS; + break; + case DefinedAtom::typeZeroFill: + this->_type = ELF::SHT_NOBITS; + case DefinedAtom::typeConstant: + this->_type = ELF::SHT_PROGBITS; + break; + default: + llvm_unreachable("Unhandled content type for section!"); + } } + template -const ArrayRef SectionChunk:: +const ArrayRef StockSectionChunk:: atoms() const { return _atoms; } - template -void SectionChunk:: - appendAtom(const DefinedAtom *atom) { +void StockSectionChunk:: + appendAtom(const DefinedAtom *atom) { // Figure out offset for atom in this section given alignment constraints. uint64_t offset = this->_size; DefinedAtom::Alignment atomAlign = atom->alignment(); @@ -413,41 +439,43 @@ void SectionChunk:: // TODO: Check content permissions and figure out what to do with .bss if ((perms & DefinedAtom::permR__) == DefinedAtom::permR__) - this->_permissions |= ELF::SHF_ALLOC; + this->_flags |= ELF::SHF_ALLOC; if ((perms & DefinedAtom::permRW_) == DefinedAtom::permRW_) - this->_permissions |= (ELF::SHF_ALLOC | ELF::SHF_WRITE); + this->_flags |= (ELF::SHF_ALLOC | ELF::SHF_WRITE); if ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) - this->_permissions |= (ELF::SHF_ALLOC | ELF::SHF_EXECINSTR); + this->_flags |= (ELF::SHF_ALLOC | ELF::SHF_EXECINSTR); } template -void SectionChunk::write(uint8_t *chunkBuffer) { +void StockSectionChunk + ::write(uint8_t *chunkBuffer) { // Each section's content is just its atoms' content. for (const auto &ai : _atoms ) { // Copy raw content of atom to file buffer. - ArrayRef content = std::get<0>(ai)->rawContent(); - uint64_t contentSize = content.size(); - if (contentSize == 0) - continue; - uint8_t *atomContent = chunkBuffer + std::get<1>(ai); - std::copy_n(content.data(), contentSize, atomContent); - - for (const Reference *ref : *std::get<0>(ai)){ - uint32_t offset = ref->offsetInAtom(); - uint64_t targetAddress = 0; - - if ( ref->target() != nullptr ) - targetAddress = _writer.addressOfAtom(ref->target()); - - uint64_t fixupAddress = _writer.addressOfAtom(std::get<0>(ai)) + offset; - _writer.kindHandler()->applyFixup(ref->kind(), ref->addend(), - &atomContent[offset], - fixupAddress, - targetAddress); + ArrayRef content = std::get<0>(ai)->rawContent(); + uint64_t contentSize = content.size(); + if (contentSize == 0) + continue; + uint8_t *atomContent = chunkBuffer + std::get<1>(ai); + std::copy_n(content.data(), contentSize, atomContent); + + for (const Reference *ref : *std::get<0>(ai)){ + uint32_t offset = ref->offsetInAtom(); + uint64_t targetAddress = 0; + + if ( ref->target() != nullptr ) + targetAddress = this->_writer.addressOfAtom(ref->target()); + + uint64_t fixupAddress = this->_writer.addressOfAtom(std::get<0>(ai)) + + offset; + this->_writer.kindHandler()->applyFixup(ref->kind(), ref->addend(), + &atomContent[offset], + fixupAddress, + targetAddress); } } } -// + //===----------------------------------------------------------------------===// // ELFStringSectionChunk //===----------------------------------------------------------------------===// @@ -456,54 +484,168 @@ ELFStringSectionChunk:: ELFStringSectionChunk(const WriterOptionsELF &options, ELFWriter &writer, StringRef secName) - : _segName("PT_NULL") - , _sectionName(secName) - , _writer(writer) - , _options(options) { + : SectionChunk(secName, "PT_NULL", + false, 0lu, 0lu, 0lu, + ELF::SHT_STRTAB, 0lu, options, + writer) { // First Add a null character. It also occupies 1 byte - _StringSection.emplace_back(""); + _stringSection.emplace_back(""); this->_size = 1; } template uint64_t ELFStringSectionChunk:: addString(StringRef symName) { - _StringSection.emplace_back(symName); - + _stringSection.emplace_back(symName); uint64_t offset = this->_size; this->_size += symName.size() + 1; return offset; } +// We need to unwrap the _stringSection and then make one large memory +// chunk of null terminated strings +template +void ELFStringSectionChunk:: + write(uint8_t *chunkBuffer) { + uint64_t chunkOffset = 0; + + for (auto it : _stringSection) { + ::memcpy(chunkBuffer + chunkOffset, it.data(), it.size()); + chunkOffset += it.size(); + ::memcpy(chunkBuffer + chunkOffset, "", 1); + chunkOffset += 1; + } +} + template const char *ELFStringSectionChunk::info() { - return _sectionName.data(); + return "String Table"; +} + +//===----------------------------------------------------------------------===// +// ELFSymbolTableChunk +//===----------------------------------------------------------------------===// +template< support::endianness target_endianness, bool is64Bits> +ELFSymbolTableChunk::ELFSymbolTableChunk + (const WriterOptionsELF &options, + ELFWriter &writer, + StringRef secName) + : SectionChunk(secName, StringRef("PT_NULL"), + false, 0, 0, 0, ELF::SHT_SYMTAB, + sizeof(Elf_Sym), options, writer) +{ + _stringSection = this->_writer.strtab(); + Elf_Sym *symbol = new (_symbolAllocate.Allocate()) Elf_Sym; + memset ((void *)symbol,0, sizeof(Elf_Sym)); + _symbolTable.push_back(symbol); + this->_link = 0; + this->_entsize = sizeof(Elf_Sym); + this->_size = sizeof(Elf_Sym); +} + +template< support::endianness target_endianness, bool is64Bits> +void ELFSymbolTableChunk::addSymbol(Elf_Sym *sym){ + _symbolTable.push_back(sym); + this->_size+= sizeof(Elf_Sym) ; +} + +/// \brief Add symbols to symbol table +/// We examine each property of atom to infer the various st_* fields in Elf*_Sym +template< support::endianness target_endianness, bool is64Bits> +void ELFSymbolTableChunk + ::addSymbol(const Atom *a, uint16_t shndx) { + Elf_Sym *symbol = new(_symbolAllocate.Allocate()) Elf_Sym; + unsigned char b = 0, t = 0; + + symbol->st_name = _stringSection->addString(a->name()); +// In relocatable files, st_value holds a section offset for a defined symbol. +// st_value is an offset from the beginning of the section that st_shndx +// identifies. After we assign file offsets we can set this value correctly. + symbol->st_size = 0; + symbol->st_shndx = shndx; + symbol->st_value = 0; +// FIXME: Need to change and account all STV* when visibilities are supported + symbol->st_other = ELF::STV_DEFAULT; + if (const DefinedAtom *da = llvm::dyn_cast(a)){ + symbol->st_size = da->size(); + lld::DefinedAtom::ContentType ct; + switch (ct = da->contentType()){ + case DefinedAtom::typeCode: + t = ELF::STT_FUNC; + break; + case DefinedAtom::typeData: + t = ELF::STT_OBJECT; + break; + case DefinedAtom::typeZeroFill: + // In relocatable files, st_value holds alignment constraints for a symbol whose + // section index is SHN_COMMON + if (this->_options.type() == ELF::ET_REL){ + t = ELF::STT_COMMON; + symbol->st_value = 1 << (da->alignment()).powerOf2; + symbol->st_shndx = ELF::SHN_COMMON; + } + break; + case DefinedAtom::typeFirstInSection: + t = ELF::STT_SECTION; + break; + // TODO:: How to find STT_FILE symbols? + default: + t = ELF::STT_NOTYPE; + } + + if (da->scope() == DefinedAtom::scopeTranslationUnit) + b = ELF::STB_LOCAL; + else if (da->merge() == DefinedAtom::mergeAsWeak) + b = ELF::STB_WEAK; + else + b = ELF::STB_GLOBAL; + } else if (const AbsoluteAtom *aa = llvm::dyn_cast(a)){ +//FIXME: Absolute atoms need more properties to differentiate each other +// based on binding and type of symbol + symbol->st_value = aa->value(); + } else { + symbol->st_value = 0; + t = ELF::STT_NOTYPE; + b = ELF::STB_LOCAL; + } + symbol->setBindingAndType(b, t); + + _symbolTable.push_back(symbol); + this->_size += sizeof(Elf_Sym); } template -StringRef ELFStringSectionChunk::sectionName() { - return _sectionName ; +void ELFSymbolTableChunk::setAttributes() { +// 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) -> bool { + return (A->getBinding() < B->getBinding());})); + uint16_t shInfo = 0; + for (auto i : _symbolTable) { + if (i->getBinding() != ELF::STB_LOCAL) + break; + shInfo++; + } + this->_shinfo = shInfo; +// we set the associated string table index in th sh_link member + this->_link = this->_writer.strtab()->ordinal() - 1; + this->_align2 = this->_options.pointerWidth(); } template -StringRef ELFStringSectionChunk:: - segmentName() const { - return _segName; +const char *ELFSymbolTableChunk::info() { + return "Symbol Table"; } -// We need to unwrap the _StringSection and then make one large memory -// chunk of null terminated strings template -void ELFStringSectionChunk:: +void ELFSymbolTableChunk:: write(uint8_t *chunkBuffer) { uint64_t chunkOffset = 0; - - for (auto it : _StringSection) { - ::memcpy(chunkBuffer + chunkOffset, it.data(), it.size()); - chunkOffset += it.size(); - ::memcpy(chunkBuffer + chunkOffset, "", 1); - chunkOffset += 1; + for (auto it : _symbolTable) { + ::memcpy(chunkBuffer + chunkOffset, it, this->_entsize); + chunkOffset += this->_entsize; } } @@ -573,7 +715,6 @@ ELFSectionHeaderChunk is64Bits> &writer) : _options(options) , _writer(writer) { - this->_size = 0; this->_align2 = 0; // The first element in the list is always NULL @@ -582,14 +723,20 @@ ELFSectionHeaderChunk _sectionInfo.push_back(nullshdr); this->_size += sizeof (Elf_Shdr); + } +template +void ELFSectionHeaderChunk::createHeaders(){ ELFStringSectionChunk *str = _writer.shstrtab(); - for (const auto &chunk : _writer.sectionChunks()) { + for (const auto &chunk : _writer.sectionChunks()) { Elf_Shdr *shdr = new (_sectionAllocate.Allocate()) Elf_Shdr; StringRef Name = chunk->sectionName(); - uint64_t offset = str->addString(Name); - shdr->sh_name = offset; + if (chunk->shStrtableOffset() == 0){ + chunk->setShStrtableOffset(str->addString(Name)); + } + shdr->sh_name = chunk->shStrtableOffset(); + shdr->sh_type = chunk->type(); shdr->sh_flags = chunk->flags(); // TODO: At the time of creation of this section header, we will not have @@ -598,72 +745,21 @@ ELFSectionHeaderChunk shdr->sh_offset = chunk->fileOffset(); shdr->sh_addr = chunk->address(); shdr->sh_size = chunk->size(); -// The next two fields have special meanings: -// sh_type sh_link sh_info -// SHT_DYNAMIC The section header index of the string -// table used by entries in the section. 0 -// SHT_HASH The section header index of the symbol -// table to which the hash table applies. 0 -// SHT_REL -// SHT_RELA The section header index of the -// associated symbol table. The section header -// index of the section -// to which the -// relocation applies. -// SHT_SYMTAB -// SHT_DYNSYM The section header index of the -// associated string table. One greater than the -// symbol table index of -// the last local symbol -// (binding STB_LOCAL). -// SHT_GROUP The section header index of the -// associated symbol table. The symbol table -// index of an entry in -// the associated symbol -// table. The name of -// the specified symbol -// table entry provides -// a signature for the -// section group. -// SHT_SYMTAB_SHNDX The section header index of -// the associated symbol table section. 0 -// None of these chunks are of the above mentioned type, so we short them. - shdr->sh_link = 0; - shdr->sh_info = 0; + shdr->sh_link = chunk->link() ; + shdr->sh_info = chunk->shinfo(); shdr->sh_addralign = chunk->align2(); - // Not a special section with fixed entries - shdr->sh_entsize = 0; + shdr->sh_entsize = chunk->entsize(); _sectionInfo.push_back(shdr); this->_size += sizeof (Elf_Shdr); + _writer.symtab()->setAttributes(); } - - // Now I add in the section string table. For some reason This seems to be - // preferred location of string sections in contemporary - // (ones that must not be named) linker(s). - Elf_Shdr *shdr = new (_sectionAllocate.Allocate()) Elf_Shdr; - // I push the name of the string table into the string table as soon as - // it is created. - shdr->sh_name = 1; - shdr->sh_type = ELF::SHT_STRTAB; - shdr->sh_flags = 0; - // NOTE: Refer to above note when assigning st_addr for other sections. - shdr->sh_addr = str->address(); - shdr->sh_offset = str->fileOffset(); - shdr->sh_size = str->size(); - shdr->sh_link = 0; - shdr->sh_info = 0; - // This section is not a loadable section, hence we do not care about - // alignment. - shdr->sh_addralign = 1; - _sectionInfo.push_back(shdr); - this->_size += sizeof (Elf_Shdr); } template StringRef ELFSectionHeaderChunk ::segmentName() const { - return "SHDR"; + return "PT_NULL"; } template @@ -702,6 +798,7 @@ class ELFWriter : public Writer { public: LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits) typedef object::Elf_Shdr_Impl Elf_Shdr; + typedef object::Elf_Sym_Impl Elf_Sym; ELFWriter(const WriterOptionsELF &options); virtual error_code writeFile(const lld::File &File, StringRef path); uint64_t addressOfAtom(const Atom *atom); @@ -715,6 +812,13 @@ public: ELFStringSectionChunk *shstrtab() { return _shstrtable; } + + ELFStringSectionChunk *strtab() { + return _strtable; + } + ELFSymbolTableChunk *symtab() { + return _symtable; + } private: void build(const lld::File &file); @@ -728,12 +832,16 @@ private: typedef llvm::DenseMap AtomToAddress; ELFStringSectionChunk *_shstrtable ; + ELFStringSectionChunk *_strtable ; + ELFSymbolTableChunk *_symtable; std::unique_ptr _referenceKindHandler; ELFSectionHeaderChunk *_sectionHeaderChunk; AtomToAddress _atomToAddress; std::vector*> _chunks; const DefinedAtom *_entryAtom; std::vector*> _sectionChunks; + std::vector*> + _stockSectionChunks; llvm::BumpPtrAllocator _chunkAllocate; }; @@ -749,7 +857,7 @@ ELFWriter template void ELFWriter::build(const lld::File &file){ - // Create objects for each chunk. +// Create objects for each chunk. createChunks(file); assignFileOffsets(); buildAtomToAddressMap(); @@ -758,68 +866,144 @@ void ELFWriter::build(const lld::File &file){ template void ELFWriter ::createChunks (const lld::File &file) { - std::map*> sectionMap; + std::map*> + sectionMap; - // We need to create hand crafted sections such as shstrtab strtab hash and - // symtab to put relevant information in ELF structures and then process the - // atoms. +// Make header chunk + ELFHeaderChunk *ehc = + new (_chunkAllocate.Allocate + >()) + ELFHeaderChunk(_options, file); + _chunks.push_back(ehc); + + _sectionHeaderChunk = new (_chunkAllocate.Allocate>()) + ELFSectionHeaderChunk + (_options, *this); + _chunks.push_back(_sectionHeaderChunk); +// We need to create hand crafted sections such as shstrtab strtab hash and +// symtab to put relevant information in ELF structures and then process the +// atoms. _shstrtable = new (_chunkAllocate.Allocate >()) ELFStringSectionChunk (_options, *this, ".shstrtab"); - _shstrtable->addString(".shstrtab"); + _shstrtable->setShStrtableOffset(_shstrtable->addString(".shstrtab")); + _sectionChunks.push_back(_shstrtable); + + _strtable = new (_chunkAllocate.Allocate + >()) + ELFStringSectionChunk + (_options, *this, ".strtab"); + _strtable->setShStrtableOffset( _shstrtable->addString(".strtab")); + _sectionChunks.push_back(_strtable); + + _symtable = new (_chunkAllocate.Allocate + >()) + ELFSymbolTableChunk + (_options, *this, ".symtab"); + _symtable->setShStrtableOffset( _shstrtable->addString(".symtab")); + _sectionChunks.push_back(_symtable); + +//TODO: implement .hash section - //we also need to process undefined atoms for (const DefinedAtom *a : file.defined() ) { - // TODO: Add sectionChoice. - // assert( atom->sectionChoice() == DefinedAtom::sectionBasedOnContent ); StringRef sectionName = a->customSectionName(); + if (a->sectionChoice() == + DefinedAtom::SectionChoice::sectionBasedOnContent) { + if (a->size() <8) + sectionName = ".sbss"; + else + sectionName = ".bss"; + } auto pos = sectionMap.find(sectionName); DefinedAtom::ContentType type = a->contentType(); - if (pos == sectionMap.end()) { - if (type != DefinedAtom::typeUnknown){ - SectionChunk - *chunk = new (_chunkAllocate.Allocate - >()) - SectionChunk - (type, sectionName, _options, *this); - - sectionMap[sectionName] = chunk; - chunk->appendAtom(a); - _sectionChunks.push_back(chunk); + if (type != DefinedAtom::typeUnknown){ + if (pos == sectionMap.end()) { + StockSectionChunk + *chunk = new(_chunkAllocate.Allocate + > + ())StockSectionChunk + (sectionName, true, type, _options, *this); + + sectionMap[sectionName] = chunk; + chunk->appendAtom(a); + _sectionChunks.push_back(chunk); + _stockSectionChunks.push_back(chunk); + + } else { + pos->second->appendAtom(a); } - } else { - pos->second->appendAtom(a); } } - //put in the Undefined atoms as well - // Make header chunk - ELFHeaderChunk *ehc = - new (_chunkAllocate.Allocate - >()) - ELFHeaderChunk(_options, file); - - _sectionHeaderChunk = new (_chunkAllocate.Allocate>()) - ELFSectionHeaderChunk - (_options, *this); - - ehc->e_shoff(ehc->size()); - ehc->e_shentsize(_sectionHeaderChunk->size()); - ehc->e_shnum(_sectionHeaderChunk->count()); - - // I am pushing string section after all sections are in. - // Hence the index will be total number of non-custom sections we have - - ehc->e_shstrndx(_sectionChunks.size() + 1); - _chunks.push_back(ehc); - _chunks.push_back(_sectionHeaderChunk); - // We have ELF header, section header. Now push rest of sections for (auto chnk : _sectionChunks) _chunks.push_back(chnk); - _chunks.push_back(_shstrtable); + +// After creating chunks, we might lay them out diffrently. +// Lets make sure symbol table, string table and section string table +// are at the end. In future we might provide knob +// to the driver to decide layout. + swapChunkPositions(*_chunks[_chunks.size() - 1], + *reinterpret_cast*>(_shstrtable)); + swapChunkPositions(*_chunks[_chunks.size() - 2], + *reinterpret_cast*>(_strtable)); + swapChunkPositions(*_chunks[_chunks.size() - 3], + *reinterpret_cast*>(_symtable)); +// We sort the _chunks vector to have all chunks as per ordianl number +// this will help to write out the chunks in the order we decided + + std::stable_sort(_chunks.begin(), _chunks.end(),([] + (const Chunk *A, + const Chunk *B) -> bool { + return (A->ordinal() < B->ordinal());})); + + std::stable_sort(_sectionChunks.begin(), _sectionChunks.end(),([] + (const SectionChunk *A, + const SectionChunk *B) -> bool { + return (A->ordinal() < B->ordinal());})); + +// Once the layout is fixed, we can now go and populate symbol table +// with correct st_shndx member. + + for (auto chnk : _sectionChunks ){ + Elf_Sym *sym = new (_chunkAllocate.Allocate())Elf_Sym; + sym->st_name = 0; + sym->st_value = 0; + sym->st_size = 0; + sym->st_other = ELF::STV_DEFAULT; +// first two chunks are not sections hence we subtract 2 but there is a +// NULL section in section table so add 1 + sym->st_shndx = chnk->ordinal() - 1 ; + sym->setBindingAndType(ELF::STB_LOCAL, ELF::STT_SECTION); + _symtable->addSymbol(sym); + } + + for (const auto ssc : _stockSectionChunks){ + for (const auto da : ssc->atoms()) { + _symtable->addSymbol(std::get<0>(da), ssc->ordinal() -1); + } + } + for (const UndefinedAtom *a : file.undefined()) { + _symtable->addSymbol(a, ELF::SHN_UNDEF); + } + + for (const AbsoluteAtom *a : file.absolute()) { + _symtable->addSymbol(a, ELF::SHN_ABS); + } + + _sectionHeaderChunk->createHeaders(); + ehc->e_shoff(ehc->size()); + ehc->e_shentsize(_sectionHeaderChunk->size()); + ehc->e_shnum(_sectionHeaderChunk->count()); +// We need to put the index of section string table in ELF header +// first two chunks are not sections so we subtract 2 to start sections +// and add 1 since we have a NULL header + ehc->e_shstrndx(_shstrtable->ordinal() - 1); } template @@ -828,13 +1012,11 @@ void ELFWriter // _atomToAddress is a DenseMap that maps an atom its file address. // std::get<1>(ai) is the offset from the start of the section to the atom. - for (auto &chunk : _sectionChunks){ + for (auto chunk : _stockSectionChunks){ for (auto &ai : chunk->atoms() ) { _atomToAddress[std::get<0>(ai)] = chunk->address() + std::get<1>(ai); } } - - } template @@ -859,11 +1041,6 @@ void ELFWriter::assignFileOffsets() { (*it)->sh_addr = chunk->address(); ++it; } - // We have taken care of all the stock sections. We need to deal with - // custom sections - // They are section string table, string table and symbol table - (*it)->sh_offset = _shstrtable->fileOffset(); - (*it)->sh_addr = _shstrtable->address(); } template @@ -895,7 +1072,7 @@ uint64_t ELFWriter Writer *createWriterELF(const WriterOptionsELF &options) { if (!options.is64Bit() && options.endianness() == llvm::support::little) - return new lld::elf::ELFWriter(options); + return new lld::elf::ELFWriter(options); else if (options.is64Bit() && options.endianness() == llvm::support::little) return new lld::elf::ELFWriter(options); else if (!options.is64Bit() && options.endianness() == llvm::support::big) @@ -905,5 +1082,4 @@ Writer *createWriterELF(const WriterOptionsELF &options) { llvm_unreachable("Invalid Options!"); } - } // namespace lld diff --git a/lld/test/elf/sections.objtxt b/lld/test/elf/sections.objtxt index 84c7871..4c6ec28 100644 --- a/lld/test/elf/sections.objtxt +++ b/lld/test/elf/sections.objtxt @@ -2,22 +2,32 @@ RUN: lld-core -reader ELF -writer ELF -o %t1 %p/Inputs/section-test.i386 | llvm- RUN: llvm-readobj %t1 | FileCheck -check-prefix=READOBJ %s RUN: elf-dump --dump-section %t1 | FileCheck -check-prefix=ED %s -OBJDUMP: 0 000000000 00000000000000000 -OBJDUMP: 1 .text 00000000a 00000000000000174 TEXT DATA -OBJDUMP: 2 .data 000000004 00000000000000180 DATA -OBJDUMP: 3 .bss 000000000 00000000000000184 BSS -OBJDUMP: 4 .special 000000004 00000000000000184 DATA -OBJDUMP: 5 .anotherspecial 000000004 00000000000000188 DATA -OBJDUMP: 6 000000000 0000000000000018c BSS -OBJDUMP: 7 .shstrtab 000000036 0000000000000018c +OBJDUMP: 0 000000000 00000000000000000 +OBJDUMP: 2 .anotherspecial 000000004 000000000000001c8 DATA +OBJDUMP: 3 .special 000000004 000000000000001cc DATA +OBJDUMP: 4 .text 00000000a 000000000000001d0 TEXT DATA +OBJDUMP: 5 .data 000000004 000000000000001dc DATA +OBJDUMP: 7 .symtab 000000150 000000000000001e0 +OBJDUMP: 8 .strtab 00000003b 00000000000000330 +OBJDUMP: 9 .shstrtab 00000004b 0000000000000036b READOBJ: File Format : ELF32-i386 READOBJ: Arch : i386 READOBJ: Address Size: 32 bits +READOBJ: Symbols +READOBJ: .anotherspecial DBG 1c8 0 1c8 formatspecific +READOBJ: .symtab DBG 1e0 0 1e0 formatspecific +READOBJ: baz FUNC 1d0 a 1d0 global +READOBJ: z DATA 1c8 4 1c8 global +READOBJ: Total: 20 ED: 'e_indent[EI_DATA]', 0x01 ED: 'e_machine', 0x0003 ED: Section 1 -ED: 'sh_addralign', 0x00000004 +ED: 'sh_addralign', 0x00000002 ED: Section 2 +ED: 'sh_addralign', 0x00000008 +ED: Section 7 +ED: 'sh_link', 0x00000008 ED: 'sh_addralign', 0x00000004 +ED: 'sh_entsize', 0x00000010