[llvm-commits] [lld] r164981 - in /lld/trunk: include/lld/ReaderWriter/WriterELF.h lib/ReaderWriter/ELF/WriterELF.cpp test/elf/sections.objtxt
Hemant Kulkarni
khemant at codeaurora.org
Mon Oct 1 16:53:20 PDT 2012
Author: khemant
Date: Mon Oct 1 18:53:20 2012
New Revision: 164981
URL: http://llvm.org/viewvc/llvm-project?rev=164981&view=rev
Log:
Emit symbol tables.
Reorganize to derive all sections from SectionChunk.
Construct section table header from SectionChunk.
Modified:
lld/trunk/include/lld/ReaderWriter/WriterELF.h
lld/trunk/lib/ReaderWriter/ELF/WriterELF.cpp
lld/trunk/test/elf/sections.objtxt
Modified: lld/trunk/include/lld/ReaderWriter/WriterELF.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/ReaderWriter/WriterELF.h?rev=164981&r1=164980&r2=164981&view=diff
==============================================================================
--- lld/trunk/include/lld/ReaderWriter/WriterELF.h (original)
+++ lld/trunk/include/lld/ReaderWriter/WriterELF.h Mon Oct 1 18:53:20 2012
@@ -31,6 +31,7 @@
: _is64Bit(false)
, _endianness(llvm::support::little)
, _type(llvm::ELF::ET_EXEC)
+ , _pointerWidth(4)
, _machine(llvm::ELF::EM_386)
{}
@@ -43,16 +44,19 @@
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 @@
bool _is64Bit;
llvm::support::endianness _endianness;
uint16_t _type;
+ uint16_t _pointerWidth;
uint16_t _machine;
};
Modified: lld/trunk/lib/ReaderWriter/ELF/WriterELF.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/WriterELF.cpp?rev=164981&r1=164980&r2=164981&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/WriterELF.cpp (original)
+++ lld/trunk/lib/ReaderWriter/ELF/WriterELF.cpp Mon Oct 1 18:53:20 2012
@@ -63,51 +63,86 @@
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<support::endianness target_endianness, bool is64Bits>
+static void swapChunkPositions(Chunk<target_endianness, is64Bits>&a,
+ Chunk<target_endianness, is64Bits>&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<const DefinedAtom*, uint64_t> AtomInfo;
-/// \brief A Section represents a set of Atoms assigned to a specific ELF
-/// Section.
+/// \brief A SectionChunk represents ELF sections
template<support::endianness target_endianness, bool is64Bits>
class SectionChunk : public Chunk<target_endianness, is64Bits> {
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<target_endianness, is64Bits> &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<AtomInfo> atoms() const;
-
-private:
+protected:
+ bool _isLoadable;
+ uint64_t _link;
+ uint64_t _shinfo;
+ uint16_t _entsize;
StringRef _segmentName;
StringRef _sectionName;
const WriterOptionsELF &_options;
ELFWriter<target_endianness, is64Bits> &_writer;
- uint32_t _flags;
- uint32_t _type;
- uint32_t _permissions;
- std::vector<AtomInfo> _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<support::endianness target_endianness, bool is64Bits>
+class StockSectionChunk : public SectionChunk<target_endianness, is64Bits> {
+public:
+ virtual StringRef segmentName() { return this->_segmentName; }
+ void appendAtom(const DefinedAtom*);
+ virtual void write(uint8_t *filebuffer);
+ const ArrayRef<AtomInfo> atoms() const;
+ StockSectionChunk(StringRef sectionName, bool loadable,
+ DefinedAtom::ContentType type,
+ const WriterOptionsELF &options,
+ ELFWriter<target_endianness, is64Bits> &writer);
+private:
+ std::vector<AtomInfo> _atoms;
+};
+
/// \brief An ELFHeaderChunk represents the Elf[32/64]_Ehdr structure at the
/// start of an ELF executable file.
template<support::endianness target_endianness, bool is64Bits>
@@ -133,8 +168,7 @@
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 @@
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<support::endianness target_endianness, bool is64Bits>
class ELFSectionHeaderChunk : public Chunk<target_endianness, is64Bits> {
public:
@@ -157,20 +188,17 @@
typedef object::Elf_Shdr_Impl<target_endianness, is64Bits> Elf_Shdr;
ELFSectionHeaderChunk(const WriterOptionsELF &Options,
ELFWriter<target_endianness, is64Bits>&);
-
+ 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<Elf_Shdr*> sectionInfo() {
return _sectionInfo;
}
- bool is64Bit() { return _options.is64Bit(); }
-
private:
const WriterOptionsELF &_options;
ELFWriter<target_endianness, is64Bits> &_writer;
@@ -184,32 +212,44 @@
/// null character. We might need more than one such chunks shstrtab for setting
/// e_shstrndx in ELHHeaderChunk and strtab for use with symtab
template<support::endianness target_endianness, bool is64Bits>
-class ELFStringSectionChunk : public Chunk<target_endianness, is64Bits> {
+class ELFStringSectionChunk : public SectionChunk<target_endianness, is64Bits> {
public:
- LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits)
ELFStringSectionChunk(const WriterOptionsELF &Options,
ELFWriter<target_endianness, is64Bits> &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<StringRef> _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<support::endianness target_endianness, bool is64Bits>
+class ELFSymbolTableChunk : public SectionChunk<target_endianness, is64Bits> {
+public:
+ typedef object::Elf_Sym_Impl<target_endianness, is64Bits> Elf_Sym;
+ ELFSymbolTableChunk(const WriterOptionsELF &options,
+ ELFWriter<target_endianness, is64Bits> &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<StringRef> _StringSection;
- StringRef _sectionName;
- ELFWriter<target_endianness, is64Bits> &_writer;
- const WriterOptionsELF &_options;
-
+ std::vector<Elf_Sym*> _symbolTable;
+ ELFStringSectionChunk<target_endianness, is64Bits> *_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 @@
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 @@
template<support::endianness target_endianness, bool is64Bits>
Chunk<target_endianness, is64Bits>::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<support::endianness target_endianness, bool is64Bits>
@@ -308,41 +348,21 @@
template<support::endianness target_endianness, bool is64Bits>
SectionChunk<target_endianness, is64Bits>::
- SectionChunk(DefinedAtom::ContentType type,
- StringRef sectionName,
- const WriterOptionsELF &options,
- ELFWriter<target_endianness, is64Bits> &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<target_endianness, is64Bits> &writer)
+ : _isLoadable(loadable)
+ , _link(link)
+ , _shinfo(info)
+ , _entsize(entsz)
+ , _segmentName(segName)
+ , _sectionName(secName)
+ , _options(op)
+ , _writer(writer)
+ , _flags(flags)
+ , _type(type)
+ , _offsetInStringTable(0) {}
template<support::endianness target_endianness, bool is64Bits>
bool SectionChunk<target_endianness, is64Bits>::occupiesNoDiskSpace() {
@@ -350,45 +370,51 @@
}
template<support::endianness target_endianness, bool is64Bits>
-StringRef SectionChunk<target_endianness, is64Bits>::segmentName() const {
- return _segmentName;
-}
-
-template<support::endianness target_endianness, bool is64Bits>
-StringRef SectionChunk<target_endianness, is64Bits>::sectionName() {
- return _sectionName;
-}
-
-template<support::endianness target_endianness, bool is64Bits>
-uint32_t SectionChunk<target_endianness, is64Bits>::flags() const {
- return _flags;
-}
-
-template<support::endianness target_endianness, bool is64Bits>
-uint32_t SectionChunk<target_endianness, is64Bits>::type() const {
- return _type;
+const char *SectionChunk<target_endianness, is64Bits>::info() {
+ return _sectionName.data();
}
-template<support::endianness target_endianness, bool is64Bits>
-uint32_t SectionChunk<target_endianness, is64Bits>::permissions() {
- return _permissions;
-}
+//===----------------------------------------------------------------------===//
+// StockSectionChunk
+//===----------------------------------------------------------------------===//
template<support::endianness target_endianness, bool is64Bits>
-const char *SectionChunk<target_endianness, is64Bits>::info() {
- return _sectionName.data();
+StockSectionChunk<target_endianness, is64Bits>::
+ StockSectionChunk(StringRef secName, bool loadable,
+ DefinedAtom::ContentType type,
+ const WriterOptionsELF &options,
+ ELFWriter<target_endianness, is64Bits> &writer)
+ : SectionChunk<target_endianness, is64Bits>(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<support::endianness target_endianness, bool is64Bits>
-const ArrayRef<AtomInfo> SectionChunk<target_endianness, is64Bits>::
+const ArrayRef<AtomInfo> StockSectionChunk<target_endianness, is64Bits>::
atoms() const {
return _atoms;
}
-
template<support::endianness target_endianness, bool is64Bits>
-void SectionChunk<target_endianness, is64Bits>::
- appendAtom(const DefinedAtom *atom) {
+void StockSectionChunk<target_endianness, is64Bits>::
+ 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 @@
// 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<support::endianness target_endianness, bool is64Bits>
-void SectionChunk<target_endianness, is64Bits>::write(uint8_t *chunkBuffer) {
+void StockSectionChunk<target_endianness, is64Bits>
+ ::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<uint8_t> 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<uint8_t> 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(const WriterOptionsELF &options,
ELFWriter<target_endianness, is64Bits> &writer,
StringRef secName)
- : _segName("PT_NULL")
- , _sectionName(secName)
- , _writer(writer)
- , _options(options) {
+ : SectionChunk<target_endianness, is64Bits>(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<support::endianness target_endianness, bool is64Bits>
uint64_t ELFStringSectionChunk<target_endianness, is64Bits>::
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<support::endianness target_endianness, bool is64Bits>
+void ELFStringSectionChunk<target_endianness, is64Bits>::
+ 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<support::endianness target_endianness, bool is64Bits>
const char *ELFStringSectionChunk<target_endianness, is64Bits>::info() {
- return _sectionName.data();
+ return "String Table";
+}
+
+//===----------------------------------------------------------------------===//
+// ELFSymbolTableChunk
+//===----------------------------------------------------------------------===//
+template< support::endianness target_endianness, bool is64Bits>
+ELFSymbolTableChunk<target_endianness, is64Bits>::ELFSymbolTableChunk
+ (const WriterOptionsELF &options,
+ ELFWriter<target_endianness, is64Bits> &writer,
+ StringRef secName)
+ : SectionChunk<target_endianness, is64Bits>(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>()) 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<target_endianness, is64Bits>::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<target_endianness, is64Bits>
+ ::addSymbol(const Atom *a, uint16_t shndx) {
+ Elf_Sym *symbol = new(_symbolAllocate.Allocate<Elf_Sym>()) 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<const DefinedAtom>(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<const AbsoluteAtom>(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<support::endianness target_endianness, bool is64Bits>
-StringRef ELFStringSectionChunk<target_endianness, is64Bits>::sectionName() {
- return _sectionName ;
+void ELFSymbolTableChunk<target_endianness, is64Bits>::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<support::endianness target_endianness, bool is64Bits>
-StringRef ELFStringSectionChunk<target_endianness, is64Bits>::
- segmentName() const {
- return _segName;
+const char *ELFSymbolTableChunk<target_endianness, is64Bits>::info() {
+ return "Symbol Table";
}
-// We need to unwrap the _StringSection and then make one large memory
-// chunk of null terminated strings
template<support::endianness target_endianness, bool is64Bits>
-void ELFStringSectionChunk<target_endianness, is64Bits>::
+void ELFSymbolTableChunk<target_endianness, is64Bits>::
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 @@
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 @@
_sectionInfo.push_back(nullshdr);
this->_size += sizeof (Elf_Shdr);
+ }
+template<support::endianness target_endianness, bool is64Bits>
+void ELFSectionHeaderChunk<target_endianness, is64Bits>::createHeaders(){
ELFStringSectionChunk<target_endianness, is64Bits> *str = _writer.shstrtab();
- for (const auto &chunk : _writer.sectionChunks()) {
+ for (const auto &chunk : _writer.sectionChunks()) {
Elf_Shdr *shdr = new (_sectionAllocate.Allocate<Elf_Shdr>()) 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 @@
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>()) 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<support::endianness target_endianness, bool is64Bits>
StringRef ELFSectionHeaderChunk<target_endianness, is64Bits>
::segmentName() const {
- return "SHDR";
+ return "PT_NULL";
}
template<support::endianness target_endianness, bool is64Bits>
@@ -702,6 +798,7 @@
public:
LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits)
typedef object::Elf_Shdr_Impl<target_endianness, is64Bits> Elf_Shdr;
+ typedef object::Elf_Sym_Impl<target_endianness, is64Bits> 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 @@
ELFStringSectionChunk<target_endianness, is64Bits> *shstrtab() {
return _shstrtable;
}
+
+ ELFStringSectionChunk<target_endianness, is64Bits> *strtab() {
+ return _strtable;
+ }
+ ELFSymbolTableChunk<target_endianness, is64Bits> *symtab() {
+ return _symtable;
+ }
private:
void build(const lld::File &file);
@@ -728,12 +832,16 @@
typedef llvm::DenseMap<const Atom*, uint64_t> AtomToAddress;
ELFStringSectionChunk<target_endianness, is64Bits> *_shstrtable ;
+ ELFStringSectionChunk<target_endianness, is64Bits> *_strtable ;
+ ELFSymbolTableChunk<target_endianness, is64Bits> *_symtable;
std::unique_ptr<KindHandler> _referenceKindHandler;
ELFSectionHeaderChunk<target_endianness, is64Bits> *_sectionHeaderChunk;
AtomToAddress _atomToAddress;
std::vector<Chunk<target_endianness, is64Bits>*> _chunks;
const DefinedAtom *_entryAtom;
std::vector<SectionChunk<target_endianness, is64Bits>*> _sectionChunks;
+ std::vector<StockSectionChunk<target_endianness, is64Bits>*>
+ _stockSectionChunks;
llvm::BumpPtrAllocator _chunkAllocate;
};
@@ -749,7 +857,7 @@
template<support::endianness target_endianness, bool is64Bits>
void ELFWriter<target_endianness, is64Bits>::build(const lld::File &file){
- // Create objects for each chunk.
+// Create objects for each chunk.
createChunks(file);
assignFileOffsets();
buildAtomToAddressMap();
@@ -758,68 +866,144 @@
template<support::endianness target_endianness, bool is64Bits>
void ELFWriter<target_endianness, is64Bits>
::createChunks (const lld::File &file) {
- std::map<StringRef, SectionChunk<target_endianness, is64Bits>*> sectionMap;
+ std::map<StringRef, StockSectionChunk<target_endianness, is64Bits>*>
+ 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<target_endianness, is64Bits> *ehc =
+ new (_chunkAllocate.Allocate
+ <ELFHeaderChunk<target_endianness, is64Bits>>())
+ ELFHeaderChunk<target_endianness, is64Bits>(_options, file);
+ _chunks.push_back(ehc);
+
+ _sectionHeaderChunk = new (_chunkAllocate.Allocate<ELFSectionHeaderChunk
+ <target_endianness, is64Bits>>())
+ ELFSectionHeaderChunk
+ <target_endianness, is64Bits>(_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<target_endianness, is64Bits>>())
ELFStringSectionChunk<target_endianness, is64Bits>
(_options, *this, ".shstrtab");
- _shstrtable->addString(".shstrtab");
+ _shstrtable->setShStrtableOffset(_shstrtable->addString(".shstrtab"));
+ _sectionChunks.push_back(_shstrtable);
+
+ _strtable = new (_chunkAllocate.Allocate
+ <ELFStringSectionChunk<target_endianness, is64Bits>>())
+ ELFStringSectionChunk<target_endianness, is64Bits>
+ (_options, *this, ".strtab");
+ _strtable->setShStrtableOffset( _shstrtable->addString(".strtab"));
+ _sectionChunks.push_back(_strtable);
+
+ _symtable = new (_chunkAllocate.Allocate
+ <ELFSymbolTableChunk<target_endianness, is64Bits>>())
+ ELFSymbolTableChunk<target_endianness, is64Bits>
+ (_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<target_endianness, is64Bits>
- *chunk = new (_chunkAllocate.Allocate
- <SectionChunk<target_endianness, is64Bits>>())
- SectionChunk<target_endianness, is64Bits>
- (type, sectionName, _options, *this);
-
- sectionMap[sectionName] = chunk;
- chunk->appendAtom(a);
- _sectionChunks.push_back(chunk);
+ if (type != DefinedAtom::typeUnknown){
+ if (pos == sectionMap.end()) {
+ StockSectionChunk<target_endianness, is64Bits>
+ *chunk = new(_chunkAllocate.Allocate
+ <StockSectionChunk<target_endianness, is64Bits>>
+ ())StockSectionChunk<target_endianness, is64Bits>
+ (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<target_endianness, is64Bits> *ehc =
- new (_chunkAllocate.Allocate
- <ELFHeaderChunk<target_endianness, is64Bits>>())
- ELFHeaderChunk<target_endianness, is64Bits>(_options, file);
+ for (auto chnk : _sectionChunks)
+ _chunks.push_back(chnk);
- _sectionHeaderChunk = new (_chunkAllocate.Allocate<ELFSectionHeaderChunk
- <target_endianness, is64Bits>>())
- ELFSectionHeaderChunk
- <target_endianness, is64Bits>(_options, *this);
+// 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<Chunk<target_endianness,
+ is64Bits>*>(_shstrtable));
+ swapChunkPositions(*_chunks[_chunks.size() - 2],
+ *reinterpret_cast<Chunk<target_endianness,
+ is64Bits>*>(_strtable));
+ swapChunkPositions(*_chunks[_chunks.size() - 3],
+ *reinterpret_cast<Chunk<target_endianness,
+ is64Bits>*>(_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<target_endianness, is64Bits> *A,
+ const Chunk<target_endianness, is64Bits> *B) -> bool {
+ return (A->ordinal() < B->ordinal());}));
+
+ std::stable_sort(_sectionChunks.begin(), _sectionChunks.end(),([]
+ (const SectionChunk<target_endianness, is64Bits> *A,
+ const SectionChunk<target_endianness, is64Bits> *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.
- ehc->e_shoff(ehc->size());
- ehc->e_shentsize(_sectionHeaderChunk->size());
- ehc->e_shnum(_sectionHeaderChunk->count());
+ for (auto chnk : _sectionChunks ){
+ Elf_Sym *sym = new (_chunkAllocate.Allocate<Elf_Sym>())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);
+ }
- // 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);
+ 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<support::endianness target_endianness, bool is64Bits>
@@ -828,13 +1012,11 @@
// _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<support::endianness target_endianness, bool is64Bits>
@@ -859,11 +1041,6 @@
(*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<support::endianness target_endianness, bool is64Bits>
@@ -895,7 +1072,7 @@
Writer *createWriterELF(const WriterOptionsELF &options) {
if (!options.is64Bit() && options.endianness() == llvm::support::little)
- return new lld::elf::ELFWriter<support::little, false>(options);
+ return new lld::elf::ELFWriter<support::little, false>(options);
else if (options.is64Bit() && options.endianness() == llvm::support::little)
return new lld::elf::ELFWriter<support::little, true>(options);
else if (!options.is64Bit() && options.endianness() == llvm::support::big)
@@ -905,5 +1082,4 @@
llvm_unreachable("Invalid Options!");
}
-
} // namespace lld
Modified: lld/trunk/test/elf/sections.objtxt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/sections.objtxt?rev=164981&r1=164980&r2=164981&view=diff
==============================================================================
--- lld/trunk/test/elf/sections.objtxt (original)
+++ lld/trunk/test/elf/sections.objtxt Mon Oct 1 18:53:20 2012
@@ -2,22 +2,32 @@
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
More information about the llvm-commits
mailing list