//===- lib/ReaderWriter/ELF/HeaderChunks.h --------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLD_READER_WRITER_ELF_HEADER_CHUNKS_H #define LLD_READER_WRITER_ELF_HEADER_CHUNKS_H #include "SegmentChunks.h" #include "llvm/Object/ELF.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ELF.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/Format.h" /// \brief An Header represents the Elf[32/64]_Ehdr structure at the /// start of an ELF executable file. namespace lld { namespace elf { template class ELFHeader : public Chunk { public: typedef llvm::object::Elf_Ehdr_Impl Elf_Ehdr; ELFHeader(const ELFLinkingContext &); void e_ident(int I, unsigned char C) { _eh.e_ident[I] = C; } void e_type(uint16_t type) { _eh.e_type = type; } void e_machine(uint16_t machine) { _eh.e_machine = machine; } void e_version(uint32_t version) { _eh.e_version = version; } void e_entry(int64_t entry) { _eh.e_entry = entry; } void e_phoff(int64_t phoff) { _eh.e_phoff = phoff; } void e_shoff(int64_t shoff) { _eh.e_shoff = shoff; } void e_flags(uint32_t flags) { _eh.e_flags = flags; } void e_ehsize(uint16_t ehsize) { _eh.e_ehsize = ehsize; } void e_phentsize(uint16_t phentsize) { _eh.e_phentsize = phentsize; } void e_phnum(uint16_t phnum) { _eh.e_phnum = phnum; } 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 fileSize() { return sizeof (Elf_Ehdr); } static inline bool classof(const Chunk *c) { return c->Kind() == Chunk::Kind::ELFHeader; } inline int getContentType() const { return Chunk::ContentType::Header; } void write(ELFWriter *writer, TargetLayout &layout, llvm::FileOutputBuffer &buffer); virtual void doPreFlight() {} void finalize() {} private: Elf_Ehdr _eh; }; template ELFHeader::ELFHeader(const ELFLinkingContext &context) : Chunk("elfhdr", Chunk::Kind::ELFHeader, context) { this->_align2 = ELFT::Is64Bits ? 8 : 4; this->_fsize = sizeof(Elf_Ehdr); this->_msize = sizeof(Elf_Ehdr); memset(_eh.e_ident, 0, llvm::ELF::EI_NIDENT); e_ident(llvm::ELF::EI_MAG0, 0x7f); e_ident(llvm::ELF::EI_MAG1, 'E'); e_ident(llvm::ELF::EI_MAG2, 'L'); e_ident(llvm::ELF::EI_MAG3, 'F'); e_ehsize(sizeof(Elf_Ehdr)); e_flags(0); } template void ELFHeader::write(ELFWriter *writer, TargetLayout &layout, llvm::FileOutputBuffer &buffer) { uint8_t *chunkBuffer = buffer.getBufferStart(); uint8_t *atomContent = chunkBuffer + this->fileOffset(); memcpy(atomContent, &_eh, fileSize()); } /// \brief An ProgramHeader represents the Elf[32/64]_Phdr structure at the /// start of an ELF executable file. template class ProgramHeader : public Chunk { public: typedef llvm::object::Elf_Phdr_Impl Elf_Phdr; typedef typename std::vector::iterator PhIterT; typedef typename std::reverse_iterator ReversePhIterT; /// \brief Find a program header entry, given the type of entry that /// we are looking for class FindPhdr { public: FindPhdr(uint64_t type, uint64_t flags, uint64_t flagsClear) : _type(type) , _flags(flags) , _flagsClear(flagsClear) { } bool operator()(const llvm::object::Elf_Phdr_Impl *j) const { return ((j->p_type == _type) && ((j->p_flags & _flags) == _flags) && (!(j->p_flags & _flagsClear))); } private: uint64_t _type; uint64_t _flags; uint64_t _flagsClear; }; ProgramHeader(const ELFLinkingContext &context) : Chunk("elfphdr", Chunk::Kind::ProgramHeader, context) { this->_align2 = ELFT::Is64Bits ? 8 : 4; resetProgramHeaders(); } bool addSegment(Segment *segment); void resetProgramHeaders() { _phi = _ph.begin(); } uint64_t fileSize() { return sizeof(Elf_Phdr) * _ph.size(); } static inline bool classof(const Chunk *c) { return c->Kind() == Chunk::Kind::ProgramHeader; } void write(ELFWriter *writer, TargetLayout &layout, llvm::FileOutputBuffer &buffer); /// \brief find a program header entry in the list of program headers ReversePhIterT findProgramHeader(uint64_t type, uint64_t flags, uint64_t flagClear) { return std::find_if(_ph.rbegin(), _ph.rend(), FindPhdr(type, flags, flagClear)); } PhIterT begin() { return _ph.begin(); } PhIterT end() { return _ph.end(); } ReversePhIterT rbegin() { return _ph.rbegin(); } ReversePhIterT rend() { return _ph.rend(); } virtual void doPreFlight() {} void finalize() {} int64_t entsize() { return sizeof(Elf_Phdr); } int64_t numHeaders() { return _ph.size(); } inline int getContentType() const { return Chunk::ContentType::Header; } private: Elf_Phdr *allocateProgramHeader(bool &allocatedNew) { Elf_Phdr *phdr; if (_phi == _ph.end()) { phdr = new (_allocator) Elf_Phdr; _ph.push_back(phdr); _phi = _ph.end(); allocatedNew = true; } else { phdr = (*_phi); ++_phi; } return phdr; } std::vector _ph; PhIterT _phi; llvm::BumpPtrAllocator _allocator; }; template bool ProgramHeader::addSegment(Segment *segment) { bool allocatedNew = false; ELFLinkingContext::OutputMagic outputMagic = this->_context.getOutputMagic(); // For segments that are not a loadable segment, we // just pick the values directly from the segment as there // wouldnt be any slices within that if (segment->segmentType() != llvm::ELF::PT_LOAD) { Elf_Phdr *phdr = allocateProgramHeader(allocatedNew); phdr->p_type = segment->segmentType(); phdr->p_offset = segment->fileOffset(); phdr->p_vaddr = segment->virtualAddr(); phdr->p_paddr = segment->virtualAddr(); phdr->p_filesz = segment->fileSize(); phdr->p_memsz = segment->memSize(); phdr->p_flags = segment->flags(); phdr->p_align = segment->align2(); this->_fsize = fileSize(); this->_msize = this->_fsize; return allocatedNew; } // For all other segments, use the slice // to derive program headers for (auto slice : segment->slices()) { Elf_Phdr *phdr = allocateProgramHeader(allocatedNew); phdr->p_type = segment->segmentType(); phdr->p_offset = slice->fileOffset(); phdr->p_vaddr = slice->virtualAddr(); phdr->p_paddr = slice->virtualAddr(); phdr->p_filesz = slice->fileSize(); phdr->p_memsz = slice->memSize(); phdr->p_flags = segment->flags(); if (outputMagic != ELFLinkingContext::OutputMagic::NMAGIC && outputMagic != ELFLinkingContext::OutputMagic::OMAGIC) phdr->p_align = (phdr->p_type == llvm::ELF::PT_LOAD) ? segment->pageSize() : slice->align2(); else phdr->p_align = slice->align2(); } this->_fsize = fileSize(); this->_msize = this->_fsize; return allocatedNew; } template void ProgramHeader::write(ELFWriter *writer, TargetLayout &layout, llvm::FileOutputBuffer &buffer) { uint8_t *chunkBuffer = buffer.getBufferStart(); uint8_t *dest = chunkBuffer + this->fileOffset(); for (auto phi : _ph) { memcpy(dest, phi, sizeof(Elf_Phdr)); dest += sizeof(Elf_Phdr); } } /// \brief An SectionHeader represents the Elf[32/64]_Shdr structure /// at the end of the file template class SectionHeader : public Chunk { public: typedef llvm::object::Elf_Shdr_Impl Elf_Shdr; SectionHeader(const ELFLinkingContext &, int32_t order); void appendSection(MergedSections *section); void updateSection(Section *section); static inline bool classof(const Chunk *c) { return c->getChunkKind() == Chunk::Kind::SectionHeader; } void setStringSection(StringTable *s) { _stringSection = s; } void write(ELFWriter *writer, TargetLayout &layout, llvm::FileOutputBuffer &buffer); virtual void doPreFlight() {} void finalize() {} inline uint64_t fileSize() { return sizeof(Elf_Shdr) * _sectionInfo.size(); } inline uint64_t entsize() { return sizeof(Elf_Shdr); } inline int getContentType() const { return Chunk::ContentType::Header; } inline uint64_t numHeaders() { return _sectionInfo.size(); } private: StringTable *_stringSection; std::vector _sectionInfo; llvm::BumpPtrAllocator _sectionAllocate; }; template SectionHeader::SectionHeader(const ELFLinkingContext &context, int32_t order) : Chunk("shdr", Chunk::Kind::SectionHeader, context) { this->_fsize = 0; this->_align2 = 8; this->setOrder(order); // The first element in the list is always NULL Elf_Shdr *nullshdr = new (_sectionAllocate.Allocate()) Elf_Shdr; ::memset(nullshdr, 0, sizeof (Elf_Shdr)); _sectionInfo.push_back(nullshdr); this->_fsize += sizeof (Elf_Shdr); } template void SectionHeader::appendSection(MergedSections *section) { Elf_Shdr *shdr = new (_sectionAllocate.Allocate()) Elf_Shdr; shdr->sh_name = _stringSection->addString(section->name()); shdr->sh_type = section->type(); shdr->sh_flags = section->flags(); shdr->sh_offset = section->fileOffset(); shdr->sh_addr = section->virtualAddr(); if (section->isLoadableSection()) shdr->sh_size = section->memSize(); else shdr->sh_size = section->fileSize(); shdr->sh_link = section->link(); shdr->sh_info = section->shinfo(); shdr->sh_addralign = section->align2(); shdr->sh_entsize = section->entsize(); _sectionInfo.push_back(shdr); } template void SectionHeader::updateSection(Section *section) { Elf_Shdr *shdr = _sectionInfo[section->ordinal()]; shdr->sh_type = section->getType(); shdr->sh_flags = section->getFlags(); shdr->sh_offset = section->fileOffset(); shdr->sh_addr = section->virtualAddr(); shdr->sh_size = section->fileSize(); shdr->sh_link = section->getLink(); shdr->sh_info = section->getInfo(); shdr->sh_addralign = section->align2(); shdr->sh_entsize = section->getEntSize(); } template void SectionHeader::write(ELFWriter *writer, TargetLayout &layout, llvm::FileOutputBuffer &buffer) { uint8_t *chunkBuffer = buffer.getBufferStart(); uint8_t *dest = chunkBuffer + this->fileOffset(); for (auto shi : _sectionInfo) { memcpy(dest, shi, sizeof(Elf_Shdr)); dest += sizeof(Elf_Shdr); } _stringSection->write(writer, layout, buffer); } } // end namespace elf } // end namespace lld #endif