[llvm-commits] LLD: patch Program Headers
Michael Spencer
bigcheesegs at gmail.com
Thu Nov 1 12:19:53 PDT 2012
On Mon, Oct 29, 2012 at 4:16 PM, Hemant Kulkarni <khemant at codeaurora.org> wrote:
> Hi,
>
>
>
> The attached patch adds machinery to assign offsets and addresses to chunks
> such that program headers can be created using them. The patch also puts in
> the mechanism to emit these headers.
>
> Please review the patch and comment on it. The patch rearranges the sections
> based on where they usually fall in an ELF file for other linkers. This
> triggered change in the tests.
>
>
>
> More test cases will follow to check corners.
>
>
>
> --
>
> Hemant Kulkarni
>
> khemant at codeaurora.org
>
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by
> the Linux Foundation
>
>
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>
> Index: include/lld/ReaderWriter/WriterELF.h
> ===================================================================
> --- include/lld/ReaderWriter/WriterELF.h (revision 166506)
> +++ include/lld/ReaderWriter/WriterELF.h (working copy)
> @@ -33,6 +33,8 @@
> , _type(llvm::ELF::ET_EXEC)
> , _pointerWidth(4)
> , _machine(llvm::ELF::EM_386)
> + , _baseAddress(0x400000)
> + , _pageSize(0x1000)
> {}
>
> /// \brief Create a specific instance of an architecture.
> @@ -45,18 +47,24 @@
> const llvm::support::endianness endian,
> const uint16_t Type,
> const uint16_t Machine,
> - uint64_t pointerWidth = 4)
> + uint64_t pointerWidth = 4,
> + uint64_t baseAddress = 0x400000,
> + uint64_t pageSize = 0x1000)
> : _is64Bit(Is64Bit)
> , _endianness(endian)
> , _type(Type)
> , _pointerWidth(pointerWidth)
> - , _machine(Machine) {}
> + , _machine(Machine)
> + , _baseAddress(baseAddress)
> + , _pageSize(pageSize) {}
>
> 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; }
> + uint64_t baseAddress() const { return _baseAddress; }
> + uint64_t pageSize() const { return _pageSize; }
>
> /// \brief Get the entry point if type() is ET_EXEC. Empty otherwise.
> StringRef entryPoint() const;
> @@ -67,6 +75,8 @@
> uint16_t _type;
> uint16_t _pointerWidth;
> uint16_t _machine;
> + uint64_t _baseAddress;
> + uint64_t _pageSize;
> };
>
> /// \brief Create a WriterELF using the given options.
> Index: lib/ReaderWriter/ELF/WriterELF.cpp
> ===================================================================
> --- lib/ReaderWriter/ELF/WriterELF.cpp (revision 166506)
> +++ lib/ReaderWriter/ELF/WriterELF.cpp (working copy)
> @@ -38,15 +38,38 @@
> #include <map>
> #include <tuple>
> #include <vector>
> +#include <algorithm>
>
> using namespace llvm;
> using namespace llvm::object;
> namespace lld {
> namespace elf {
>
> +// The group decides where sections of similar permissions reside
> +// inside a file. This is also used to create program headers. Each group
> +// will be in a new segment.
> +enum {
> + CG_INVALID = 0x0,
> + CG_HEADER = 0x1,
> + CG_RWX = 0x3,
> + CG_RX = 0x4,
> + CG_R = 0x5,
> + CG_RW = 0x6,
> + CG_WX = 0x7,
> + CG_W = 0x8,
> + CG_X = 0x9,
> + CG_NO_LOAD = 0xFE,
> + CG_FILE_END = 0xFF
> +};
> +
> template<support::endianness target_endianness, bool is64Bits>
> class ELFWriter;
>
> +// Each "Chunk" (explained below) should be arranged in a weak strict order
> +// This is done to minimize memory utilization when creating program headers.
> +// This will remain in place till a more felxible mechanism of moving chunks
> +// around and packing for memory efficiency is put in place.
> +
This should use doxygen member grouping to group all the chunks.
http://www.stack.nl/~dimitri/doxygen/grouping.html#memgroup
For example:
/// \name Chunks
/// Each "Chunk" [...]
/// around and packing for memory efficiency is put in place.
/// \{
All the chunks go in here.
/// \}
> /// \brief A Chunk is a contiguous range of space.
> template<support::endianness target_endianness, bool is64Bits>
> class Chunk {
> @@ -65,14 +88,30 @@
> static uint64_t alignTo(uint64_t value, uint8_t align2);
> uint64_t ordinal() const { return _ordinal;}
> void setOrdinal(uint64_t newVal) { _ordinal = newVal;}
> -
> + void setGroup(uint16_t val) { _group = val;}
> + uint16_t group() const { return _group;}
> + void init();
> + bool isLoadable() { return _isLoadable; }
> + void isLoadable(uint64_t val) { _isLoadable = val; }
> + enum chunkKind {
> + headerKind, // This is a header chunk
> + sectionKind // chunk represents a section
> + };
The enum needs to follow the coding standard.
http://llvm.org/docs/CodingStandards.html#name-types-functions-variables-and-enumerators-properly
Also, we should be using enum class. In this case I would do:
enum class Kind {
Header,
Section
};
> + chunkKind getChunkKind() const { return _cKind; }
> + static inline bool classof(const Chunk<target_endianness, is64Bits>*)
> + { return true;}
This is a weird place to indent the body to.
> +private:
> + const chunkKind _cKind;
> protected:
> Chunk();
> + Chunk(chunkKind K): _cKind(K) { this->init();}
> uint64_t _size;
> uint64_t _address;
> uint64_t _fileOffset;
> uint64_t _align2;
> uint64_t _ordinal;
> + uint16_t _group;
> + bool _isLoadable;
> };
>
> template<support::endianness target_endianness, bool is64Bits>
> @@ -85,6 +124,16 @@
> b.setOrdinal(tempOrdinal);
> }
>
> +template<support::endianness target_endianness, bool is64Bits>
> +struct ChunkComparator {
> + bool operator()(uint16_t A, Chunk<target_endianness, is64Bits> *B) {
> + return (A < B->group());
Don't put parens around this.
> + }
> + bool operator()(Chunk<target_endianness, is64Bits> *A, uint16_t B) {
> + return (A->group() < B);
> + }
> +};
> +
MSVC doesn't like this in debug mode. The fix is to add:
#if defined(_ITERATOR_DEBUG_LEVEL) && _ITERATOR_DEBUG_LEVEL == 2
bool operator()(Chunk<target_endianness, is64Bits> *A,
Chunk<target_endianness, is64Bits> *B) {
return A->group() < B->group();
}
#endif
> /// Pair of atom and offset in section.
> typedef std::tuple<const DefinedAtom*, uint64_t> AtomInfo;
>
> @@ -100,20 +149,22 @@
> void setShStrtableOffset (uint64_t val) {
> _offsetInStringTable = val; }
> uint32_t flags() { return _flags; }
> - uint32_t type() { return _type; }
> + uint32_t type() const { 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);
> + static inline bool
> + classof(const SectionChunk<target_endianness, is64Bits> *s) { return true;}
>
> + static inline bool classof(const Chunk<target_endianness, is64Bits> *c) {
> + return c->getChunkKind() == Chunk<target_endianness, is64Bits>::sectionKind;
> + }
> protected:
> - bool _isLoadable;
> uint64_t _link;
> uint64_t _shinfo;
> uint16_t _entsize;
> @@ -173,6 +224,13 @@
> virtual StringRef segmentName() const;
> virtual void write(uint8_t *fileBuffer);
> virtual const char *info();
> + static inline bool
> + classof(const ELFHeaderChunk<target_endianness, is64Bits> *s) {
> + return true;
> + }
Reflow this. It's indented to the wrong level.
> + static inline bool classof(const Chunk<target_endianness, is64Bits> *c) {
> + return c->getChunkKind() == Chunk<target_endianness, is64Bits>::headerKind;
> + }
>
> private:
> Elf_Ehdr _eh;
> @@ -192,12 +250,20 @@
> virtual StringRef segmentName() const;
> virtual void write(uint8_t *filebuffer);
> virtual const char *info();
> - void computeSize(const lld::File &file);
> + void computeSize();
> uint16_t count();
> uint16_t size();
> + void fixOffsets();
> const ArrayRef<Elf_Shdr*> sectionInfo() {
> return _sectionInfo;
> }
> + static inline bool
> + classof(const ELFSectionHeaderChunk<target_endianness, is64Bits> *s) {
> + return true;
> + }
Same.
> + static inline bool classof(const Chunk<target_endianness, is64Bits> *c) {
> + return c->getChunkKind() == Chunk<target_endianness, is64Bits>::headerKind;
> + }
>
> private:
> const WriterOptionsELF &_options;
> @@ -250,23 +316,41 @@
> 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.
> +/// \brief ELFProgramHeaderChunk represents the Elf[32/64]_Phdr structure near
> +/// the start of an ELF executable file. ELFHeader's e_phentsize and e_phnum
> +/// show the number of entries in table and size of each one.
> template<support::endianness target_endianness, bool is64Bits>
> class ELFProgramHeaderChunk : public Chunk<target_endianness, is64Bits> {
> public:
> LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits)
> - ELFProgramHeaderChunk(ELFHeaderChunk<target_endianness, is64Bits>&,
> - const WriterOptionsELF &options,
> - const File &file);
> + typedef object::Elf_Phdr<target_endianness, is64Bits> Elf_Phdr;
> + ELFProgramHeaderChunk(const WriterOptionsELF &options,
> + ELFWriter<target_endianness, is64Bits> &);
>
> virtual StringRef segmentName() const;
> virtual void write(uint8_t *filebuffer);
> virtual const char *info();
> + void createPHeaders();
> + uint64_t computeNumber();
> + static inline bool
> + classof(const ELFHeaderChunk<target_endianness, is64Bits> *s) {
> + return true;
> + }
Same.
> + static inline bool classof(const Chunk<target_endianness, is64Bits> *c) {
> + return c->getChunkKind() == Chunk<target_endianness, is64Bits>::headerKind;
> + }
>
> private:
> -// TODO: Replace this with correct ELF::* type method
> + typedef typename std::vector<SectionChunk<target_endianness, is64Bits>*>
> + ::iterator secIterator;
> + const WriterOptionsELF &_options;
> + ELFWriter<target_endianness, is64Bits> &_writer;
> + std::vector<Elf_Phdr*> _programHeaders;
> + llvm::BumpPtrAllocator _headerAllocate;
> + typedef std::pair<uint64_t, uint64_t> sectionRange;
> + std::vector<sectionRange> _segments;
> + std::map<uint16_t, uint16_t> _groupToPF;
> +
> };
>
> //===----------------------------------------------------------------------===//
> @@ -274,9 +358,19 @@
> //===----------------------------------------------------------------------===//
>
> 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.
> +Chunk<target_endianness, is64Bits>::Chunk(){
> + this->init();
> +}
> +
> +template<support::endianness target_endianness, bool is64Bits>
> +void Chunk<target_endianness, is64Bits>::init(){
> + this->_size = 0;
> + this->_address = 0;
> + this->_fileOffset = 0;
> + this->_align2 = 0;
> + this->_group = CG_INVALID;
> + this->_isLoadable = false;
> + // 0 and 1 are reserved. 0 for ELF header and 1 for program header.
> static uint64_t orderNumber = 0;
> _ordinal = orderNumber++;
> }
> @@ -352,7 +446,8 @@
> 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)
> + : Chunk<target_endianness, is64Bits>(Chunk<target_endianness, is64Bits>
> + ::sectionKind)
> , _link(link)
> , _shinfo(info)
> , _entsize(entsz)
> @@ -362,8 +457,10 @@
> , _writer(writer)
> , _flags(flags)
> , _type(type)
> - , _offsetInStringTable(0) {}
> -
> + , _offsetInStringTable(0) {
> + this->isLoadable(loadable);
> + }
This seems indented wrong.
> +//FIXME: We need to make decision here for every section created
> template<support::endianness target_endianness, bool is64Bits>
> bool SectionChunk<target_endianness, is64Bits>::occupiesNoDiskSpace() {
> return false;
> @@ -388,6 +485,13 @@
> loadable, 0lu, 0lu, 0u, 0lu, 0lu,
> options, writer) {
> this->_segmentName = this->_isLoadable ? "PT_LOAD" : "PT_NULL" ;
> + // If the section is custom loadable section, group should be set explicitly.
> + // Stock non loadable section go as NO_LOAD and others will get their
> + // group determined by the atoms contained within. Many constant
> + // sections will have no symbols but the constants are referred as
> + // offset from start symbol, hence there may not be any defined atoms being
> + // appended to them, we force them at time of creation to CG_R
> + this->setGroup(this->isLoadable() ? CG_INVALID : CG_NO_LOAD);
> switch(type) {
> case DefinedAtom::typeCode:
> this->_type = ELF::SHT_PROGBITS;
> @@ -400,6 +504,8 @@
> break;
> case DefinedAtom::typeConstant:
> this->_type = ELF::SHT_PROGBITS;
> + this->_flags = ELF::SHF_ALLOC;
> + this->setGroup(CG_R);
> break;
> default:
> llvm_unreachable("Unhandled content type for section!");
> @@ -416,6 +522,8 @@
> template<support::endianness target_endianness, bool is64Bits>
> void StockSectionChunk<target_endianness, is64Bits>::
> appendAtom(const DefinedAtom *atom) {
> + static uint16_t groupArray[] = {CG_INVALID, CG_W, CG_R, CG_RW, CG_X,
> + CG_WX, CG_RX, CG_RWX};
> // Figure out offset for atom in this section given alignment constraints.
> uint64_t offset = this->_size;
> DefinedAtom::Alignment atomAlign = atom->alignment();
> @@ -437,14 +545,16 @@
> this->_size = offset + atom->size();
> // Update permissions
> DefinedAtom::ContentPermissions perms = atom->permissions();
> -
> - // TODO: Check content permissions and figure out what to do with .bss
> +
> if ((perms & DefinedAtom::permR__) == DefinedAtom::permR__)
> this->_flags |= ELF::SHF_ALLOC;
> if ((perms & DefinedAtom::permRW_) == DefinedAtom::permRW_)
> this->_flags |= (ELF::SHF_ALLOC | ELF::SHF_WRITE);
> if ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X)
> this->_flags |= (ELF::SHF_ALLOC | ELF::SHF_EXECINSTR);
> + if (atom->contentType() == DefinedAtom::typeZeroFill)
> + this->_flags |= (ELF::SHF_ALLOC | ELF::SHF_WRITE);
> + this->setGroup(groupArray[this->_flags]);
> }
>
> template<support::endianness target_endianness, bool is64Bits>
> @@ -492,6 +602,7 @@
> // First Add a null character. It also occupies 1 byte
> _stringSection.emplace_back("");
> this->_size = 1;
> + this->setGroup(CG_NO_LOAD);
> }
>
> template<support::endianness target_endianness, bool is64Bits>
> @@ -543,6 +654,8 @@
> this->_link = 0;
> this->_entsize = sizeof(Elf_Sym);
> this->_size = sizeof(Elf_Sym);
> + this->_align2 = this->_options.pointerWidth();
> + this->setGroup(CG_NO_LOAD);
> }
>
> template< support::endianness target_endianness, bool is64Bits>
> @@ -670,7 +783,9 @@
> template<support::endianness target_endianness, bool is64Bits>
> ELFHeaderChunk<target_endianness, is64Bits>
> ::ELFHeaderChunk(const WriterOptionsELF &options,
> - const File &File) {
> + const File &File)
> + : Chunk<target_endianness, is64Bits>(Chunk<target_endianness, is64Bits>
> + ::headerKind){
> this->_size = size();
> e_ident(ELF::EI_MAG0, 0x7f);
> e_ident(ELF::EI_MAG1, 'E');
> @@ -689,7 +804,7 @@
> e_version(1);
>
> e_entry(0ULL);
> - e_phoff(this->_size);
> + e_phoff(0);
> e_shoff(0ULL);
>
> e_flags(0);
> @@ -699,6 +814,7 @@
> e_shentsize(0);
> e_shnum(0);
> e_shstrndx(0);
> + this->setGroup(CG_HEADER);
> }
>
> template<support::endianness target_endianness, bool is64Bits>
> @@ -730,7 +846,9 @@
> ::ELFSectionHeaderChunk(const WriterOptionsELF& options,
> ELFWriter<target_endianness,
> is64Bits> &writer)
> - : _options(options)
> + : Chunk<target_endianness, is64Bits>(Chunk<target_endianness, is64Bits>
> + ::headerKind)
> + , _options(options)
> , _writer(writer) {
> this->_size = 0;
> this->_align2 = 0;
> @@ -738,11 +856,32 @@
> Elf_Shdr *nullshdr = new (_sectionAllocate.Allocate<Elf_Shdr>()) Elf_Shdr;
> ::memset(nullshdr, 0, sizeof (Elf_Shdr));
> _sectionInfo.push_back(nullshdr);
> -
> this->_size += sizeof (Elf_Shdr);
> + this->setGroup(CG_FILE_END);
> }
>
> +
> template<support::endianness target_endianness, bool is64Bits>
> +void ELFSectionHeaderChunk<target_endianness, is64Bits>::computeSize(){
> + this->_size = (this->_writer.sectionChunks().size() + 1) * sizeof(Elf_Shdr);
> +}
> +
> +template<support::endianness target_endianness, bool is64Bits>
> +void ELFSectionHeaderChunk<target_endianness, is64Bits>::fixOffsets(){
> + auto it = _sectionInfo.begin();
> + auto sections = _writer.sectionChunks();
> + // First section is a NULL section with no sh_offset fix
> + (*it)->sh_offset = 0;
> + (*it)->sh_addr = 0;
> + ++it;
> + for (auto &chunk : sections){
> + (*it)->sh_offset = chunk->fileOffset();
> + (*it)->sh_addr = chunk->address();
> + ++it;
> + }
> +}
> +
> +template<support::endianness target_endianness, bool is64Bits>
> void ELFSectionHeaderChunk<target_endianness, is64Bits>::createHeaders(){
> ELFStringSectionChunk<target_endianness, is64Bits> *str = _writer.shstrtab();
>
> @@ -805,8 +944,113 @@
> //===----------------------------------------------------------------------===//
> // ELFProgramHeaderChunk
> //===----------------------------------------------------------------------===//
> -// TODO: Implement the methods
> +template<support::endianness target_endianness, bool is64Bits>
> +ELFProgramHeaderChunk<target_endianness, is64Bits>
> + ::ELFProgramHeaderChunk(const WriterOptionsELF &options,
> + ELFWriter<target_endianness, is64Bits>
> + &writer)
> + : Chunk<target_endianness, is64Bits>(Chunk<target_endianness, is64Bits>
> + ::headerKind)
> + , _options(options)
> + , _writer(writer) {
> + this->_align2 = 0;
> + this->setGroup(CG_HEADER);
> + _groupToPF[CG_RWX] = ELF::PF_R | ELF::PF_W | ELF::PF_X;
> + _groupToPF[CG_RW] = ELF::PF_R | ELF::PF_W;
> + _groupToPF[CG_RX] = ELF::PF_R | ELF::PF_X;
> + _groupToPF[CG_R] = ELF::PF_R;
> + _groupToPF[CG_W] = ELF::PF_W;
> + _groupToPF[CG_WX] = ELF::PF_W | ELF::PF_X;
> + _groupToPF[CG_X] = ELF::PF_X;
> + }
>
> +template<support::endianness target_endianness, bool is64Bits>
> +void ELFProgramHeaderChunk<target_endianness, is64Bits>::createPHeaders() {
> +
> + //TODO Once dynamic linking is supported, implement PHDR segment
> + // Implement mechanism inside this class to correctly find
> + // attributes for sections such as eh_frame, note etc
> + // when they are supported.
> + const uint16_t seg[] = { CG_RWX, CG_RX, CG_R, CG_RW, CG_WX, CG_W, CG_X };
> + std::pair<secIterator, secIterator> sr;
> + auto sections = _writer.sectionChunks();
> + _programHeaders.clear();
> + this->_size = 0;
> + for (auto i : seg) {
> + uint64_t size = 0, mSize = 0;
> + sr = std::equal_range(sections.begin(), sections.end(),
> + i, ChunkComparator<target_endianness, is64Bits>());
sr and i need more descriptive names.
> + if (static_cast<int>(sr.first - sr.second) != 0) {
Why does this need a static_cast? And can't this just be sr.first != sr.second?
> + // FIXME: fix occupiesNoDiskSpace() function in Chunks class
> + auto j = sr.first, k = j + 1;
These need better names.
> + // Since this group has a section, atleast this is a part of segment
> + size = (*j)->occupiesNoDiskSpace() ? 0 : (*j)->size();
> + mSize = (*j)->size();
> + for (; k != sr.second; k++) {
> + // This means there are more than 1 sections of same permissions
> + if ((*k)->fileOffset() - (*j)->fileOffset() + size >
> + _options.pageSize()) {
> + // we have a case where padding zeros span more than a page
> + // we can skip those pages.
> + Elf_Phdr *phdr = new(_headerAllocate.Allocate<Elf_Phdr>()) Elf_Phdr;
> + phdr->p_type = ELF::PT_LOAD;
> + phdr->p_offset = (*j)->fileOffset();
> + phdr->p_vaddr = (*j)->address();
> + phdr->p_paddr = phdr->p_vaddr;
> + phdr->p_filesz = size;
> + // memory size may be more than file size if there are sections
> + // that do not occupy space on disk such as .bss
> + phdr->p_memsz = mSize;
> + phdr->p_flags = _groupToPF[i];
> + phdr->p_align = _options.pageSize();
> + _programHeaders.push_back(phdr);
> + this->_size += sizeof(Elf_Phdr);
> + j = k;
> + size = (*j)->occupiesNoDiskSpace() ? 0 : (*j)->size();
> + mSize = (*j)->size();
> + } else {
> + size = (*k)->fileOffset() - (*j)->fileOffset() +
> + ((*k)->occupiesNoDiskSpace() ? 0 : (*k)->size()) ;
> + mSize = (*k)->fileOffset() - (*j)->fileOffset() + (*k)->size();
> + }
> + }
Unexpected deindent here.
> + Elf_Phdr *phdr = new(_headerAllocate.Allocate<Elf_Phdr>()) Elf_Phdr;
> + phdr->p_type = ELF::PT_LOAD;
> + phdr->p_offset = (*j)->fileOffset();
> + phdr->p_vaddr = (*j)->address();
> + phdr->p_paddr = phdr->p_vaddr;
> + phdr->p_filesz = size;
> + phdr->p_memsz = mSize;
> + phdr->p_flags = _groupToPF[i];
> + phdr->p_align = _options.pageSize();
> + _programHeaders.push_back(phdr);
> + this->_size += sizeof(Elf_Phdr);
> + }
> + }
> +}
> +
> +template<support::endianness target_endianness, bool is64Bits>
> +uint64_t ELFProgramHeaderChunk<target_endianness, is64Bits>::computeNumber() {
> + return _programHeaders.size();
> +}
> +template<support::endianness target_endianness, bool is64Bits>
> +const char *ELFProgramHeaderChunk<target_endianness, is64Bits>::info() {
> + return "elf_program_header";
> +}
> +
> +template<support::endianness target_endianness, bool is64Bits>
> +void ELFProgramHeaderChunk<target_endianness, is64Bits>
> + ::write(uint8_t *chunkBuffer) {
> + for (const auto si : _programHeaders) {
> + ::memcpy(chunkBuffer, si, sizeof(*si));
> + chunkBuffer += sizeof (*si);
> + }
> +}
> +template<support::endianness target_endianness, bool is64Bits>
> +StringRef ELFProgramHeaderChunk<target_endianness, is64Bits>
> + ::segmentName() const {
> + return "PT_NULL";
> +}
> //===----------------------------------------------------------------------===//
> // ELFWriter Class
> //===----------------------------------------------------------------------===//
> @@ -816,24 +1060,26 @@
> 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;
> + typedef object::Elf_Phdr<target_endianness, is64Bits> Elf_Phdr;
> ELFWriter(const WriterOptionsELF &options);
> virtual error_code writeFile(const lld::File &File, StringRef path);
> uint64_t addressOfAtom(const Atom *atom);
> - ArrayRef<Chunk<target_endianness, is64Bits>*> chunks() { return _chunks; }
> + std::vector<Chunk<target_endianness, is64Bits>*> chunks() const {
> + return _chunks; }
properly flow this.
> KindHandler *kindHandler() { return _referenceKindHandler.get(); }
>
> - std::vector<SectionChunk<target_endianness, is64Bits>*> sectionChunks() {
> + std::vector<SectionChunk<target_endianness, is64Bits>*> sectionChunks() const {
> return _sectionChunks ;
> }
>
> - ELFStringSectionChunk<target_endianness, is64Bits> *shstrtab() {
> + ELFStringSectionChunk<target_endianness, is64Bits> *shstrtab() const {
> return _shstrtable;
> }
>
> - ELFStringSectionChunk<target_endianness, is64Bits> *strtab() {
> + ELFStringSectionChunk<target_endianness, is64Bits> *strtab() const {
> return _strtable;
> }
> - ELFSymbolTableChunk<target_endianness, is64Bits> *symtab() {
> + ELFSymbolTableChunk<target_endianness, is64Bits> *symtab() const {
> return _symtable;
> }
>
> @@ -847,7 +1093,10 @@
> /// \brief AtomToAddress: Is a mapping from an Atom to the address where
> /// it will live in the output file.
> typedef llvm::DenseMap<const Atom*, uint64_t> AtomToAddress;
> -
> + typedef typename std::vector<Chunk<target_endianness, is64Bits>*>
> + ::iterator chunkIterator;
> + ELFProgramHeaderChunk<target_endianness, is64Bits> *_phdr;
> + ELFHeaderChunk<target_endianness, is64Bits> *ehc;
> ELFStringSectionChunk<target_endianness, is64Bits> *_shstrtable ;
> ELFStringSectionChunk<target_endianness, is64Bits> *_strtable ;
> ELFSymbolTableChunk<target_endianness, is64Bits> *_symtable;
> @@ -878,7 +1127,22 @@
> // Create objects for each chunk.
> createChunks(file);
> assignFileOffsets();
> + _phdr->createPHeaders();
> + _sectionHeaderChunk->createHeaders();
> + // Creating program headers changed its size. so we need to re-assign offsets
> + assignFileOffsets();
> + _sectionHeaderChunk->fixOffsets();
> + _phdr->createPHeaders();
> buildAtomToAddressMap();
> + 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);
> + ehc->e_phnum(_phdr->computeNumber());
> + ehc->e_phoff(_phdr->fileOffset());
> + ehc->e_phentsize(sizeof(Elf_Phdr));
> }
>
> template<support::endianness target_endianness, bool is64Bits>
> @@ -888,17 +1152,17 @@
> sectionMap;
>
> // Make header chunk
> - ELFHeaderChunk<target_endianness, is64Bits> *ehc =
> - new (_chunkAllocate.Allocate
> + ehc = new (_chunkAllocate.Allocate
> <ELFHeaderChunk<target_endianness, is64Bits>>())
> ELFHeaderChunk<target_endianness, is64Bits>(_options, file);
> _chunks.push_back(ehc);
> +
> + _phdr = new (_chunkAllocate.Allocate
> + <ELFProgramHeaderChunk<target_endianness, is64Bits>>())
> + ELFProgramHeaderChunk<target_endianness, is64Bits>(_options,
> + *this);
> + _chunks.push_back(_phdr);
>
> - _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.
> @@ -957,48 +1221,63 @@
> for (auto chnk : _sectionChunks)
> _chunks.push_back(chnk);
>
> -// 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
> + _sectionHeaderChunk = new (_chunkAllocate.Allocate<ELFSectionHeaderChunk
> + <target_endianness, is64Bits>>())
> + ELFSectionHeaderChunk
> + <target_endianness, is64Bits>(_options, *this);
> + _chunks.push_back(_sectionHeaderChunk);
>
> - 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());}));
> +// We sort the chunks based on the group they belong to
> + std::stable_sort(_chunks.begin(), _chunks.end(), ([]
> + (const Chunk<target_endianness, is64Bits> *A,
> + const Chunk<target_endianness, is64Bits> *B) -> bool {
> + if (A->group() == CG_INVALID || B->group() == CG_INVALID)
> + llvm_unreachable("Invalid group number");
> + return (A->group() < B->group());}));
This is really hard to read.
std::stable_sort(_chunks.begin(), _chunks.end(),
[](const Chunk<target_endianness, is64Bits> *A,
const Chunk<target_endianness, is64Bits> *B) -> bool {
if (A->group() == CG_INVALID || B->group() == CG_INVALID)
llvm_unreachable("Invalid group number");
return A->group() < B->group();
});
Also get rid of the exra parens around the lambda and return.
> +// The CG_RW group also has to be arranged such that all
> +// SHT_NOBITS type of sections (.*bss) are at end of this
> +// "partition" of group.
Indent comments to the level of the code they describe.
> + chunkIterator cI;
> + std::pair<chunkIterator, chunkIterator> range;
> + range = std::equal_range(_chunks.begin() + 2, _chunks.end() - 1, CG_RW,
> + ChunkComparator<target_endianness, is64Bits>());
> +
> + cI = std::stable_partition(range.first, range.second, ([]
> + (const Chunk<target_endianness, is64Bits> *A)
> + -> bool {
> + auto X = llvm::dyn_cast
> + <SectionChunk<target_endianness,
> + is64Bits>>(A);
> + return (X->type() != ELF::SHT_NOBITS);}));
Same issue as above.
cI = std::stable_partition(range.first, range.second,
[](const Chunk<target_endianness, is64Bits> *A) -> bool {
auto X = llvm::dyn_cast<SectionChunk<target_endianness, is64Bits>>(A);
return X->type() != ELF::SHT_NOBITS;
});
>
> +// We reassign all the ordinals since its needed when making headers and
> +// populating symbol table.
> + for (auto chnk : _chunks) {
> + static uint64_t i = 0;
Why is this static? That seems very broken.
> + chnk->setOrdinal(i++);
> + }
> +
> +//We sort the sections as per new ordinal set after group sorting.
> 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.
>
> - 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);
> - }
> -
> +// Populate symbol table with correct st_shndx member.
> + if (_options.type() == ELF::ET_REL) {
> + for (auto chnk : _sectionChunks ){
Space before {.
> + Elf_Sym *sym = new (_chunkAllocate.Allocate<Elf_Sym>())Elf_Sym;
Space before 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);
> @@ -1011,15 +1290,6 @@
> 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>
> @@ -1040,23 +1310,38 @@
> DEBUG_WITH_TYPE("WriterELF-layout", dbgs()
> << "assign file offsets:\n");
> uint64_t offset = 0;
> - uint64_t address = 0;
> - for (auto chunk : _chunks) {
> -
> - chunk->assignFileOffset(offset, address);
> + uint64_t address = _options.baseAddress();
> + uint16_t chunkGroup;
> + static bool secondPass = false;
This shouldn't be static. It makes the entire writer only usable once. And
breaks multithreading.
> + auto chunkIt = _chunks.begin();
> + // first (two in case of ET_EXEC or ET_DYN) chunks is (are) not section(s)
> + (*chunkIt)->assignFileOffset(offset, address);
> + chunkIt++;
> + if (_options.type() == ELF::ET_EXEC ||
> + _options.type() == ELF::ET_DYN) {
> + (*chunkIt)->assignFileOffset(offset, address);
> + chunkIt++;
Indendation?
> }
> - //TODO: We need to fix all file offsets inside various ELF section headers
> - std::vector<Elf_Shdr*> secInfo = _sectionHeaderChunk->sectionInfo();
> - typename std::vector<Elf_Shdr*>::iterator it = secInfo.begin();
> - // First section is a NULL section with no sh_offset fix
> - (*it)->sh_offset = 0;
> - (*it)->sh_addr = 0;
> - ++it;
> - for (auto &chunk : _sectionChunks){
> - (*it)->sh_offset = chunk->fileOffset();
> - (*it)->sh_addr = chunk->address();
> - ++it;
> + while (chunkIt != (_chunks.end() - 1) ) {
> + (*chunkIt)->assignFileOffset(offset, address);
> + if (_options.type() == ELF::ET_EXEC ||
> + _options.type() == ELF::ET_DYN) {
> + chunkGroup = (*chunkIt)->group();
> + chunkIt++;
> + // If the chunk group changes we start on new page
> + if (chunkGroup != (*chunkIt)->group() && (*chunkIt)->group() != CG_NO_LOAD
> + && (*chunkIt)->group() != CG_FILE_END)
> + address = address + _options.pageSize();
> + } else {
> + chunkIt++;
> + }
> }
> + (*chunkIt)->assignFileOffset(offset, address);
> + if (secondPass) {
> + ehc->e_shoff(_sectionHeaderChunk->fileOffset());
> + } else {
> + secondPass = true;
> + }
> }
>
> template<support::endianness target_endianness, bool is64Bits>
>
- Michael Spencer
More information about the llvm-commits
mailing list