353 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			353 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===- 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 ELFT> class ELFHeader : public Chunk<ELFT> {
 | |
| public:
 | |
|   typedef llvm::object::Elf_Ehdr_Impl<ELFT> 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<ELFT> *c) {
 | |
|     return c->Kind() == Chunk<ELFT>::Kind::ELFHeader;
 | |
|   }
 | |
| 
 | |
|   inline int getContentType() const { return Chunk<ELFT>::ContentType::Header; }
 | |
| 
 | |
|   void write(ELFWriter *writer, llvm::FileOutputBuffer &buffer);
 | |
| 
 | |
|   virtual void doPreFlight() {}
 | |
| 
 | |
|   void finalize() {}
 | |
| 
 | |
| private:
 | |
|   Elf_Ehdr _eh;
 | |
| };
 | |
| 
 | |
| template <class ELFT>
 | |
| ELFHeader<ELFT>::ELFHeader(const ELFLinkingContext &context)
 | |
|     : Chunk<ELFT>("elfhdr", Chunk<ELFT>::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 <class ELFT>
 | |
| void ELFHeader<ELFT>::write(ELFWriter *writer, 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 ELFT>
 | |
| class ProgramHeader : public Chunk<ELFT> {
 | |
| public:
 | |
|   typedef llvm::object::Elf_Phdr_Impl<ELFT> Elf_Phdr;
 | |
|   typedef typename std::vector<Elf_Phdr *>::iterator PhIterT;
 | |
|   typedef typename std::reverse_iterator<PhIterT> 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<ELFT> *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<ELFT>("elfphdr", Chunk<ELFT>::Kind::ProgramHeader, context) {
 | |
|     this->_align2 = ELFT::Is64Bits ? 8 : 4;
 | |
|     resetProgramHeaders();
 | |
|   }
 | |
| 
 | |
|   bool addSegment(Segment<ELFT> *segment);
 | |
| 
 | |
|   void resetProgramHeaders() { _phi = _ph.begin(); }
 | |
| 
 | |
|   uint64_t  fileSize() {
 | |
|     return sizeof(Elf_Phdr) * _ph.size();
 | |
|   }
 | |
| 
 | |
|   static inline bool classof(const Chunk<ELFT> *c) {
 | |
|     return c->Kind() == Chunk<ELFT>::Kind::ProgramHeader;
 | |
|   }
 | |
| 
 | |
|   void write(ELFWriter *writer, 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<ELFT>::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<Elf_Phdr *> _ph;
 | |
|   PhIterT _phi;
 | |
|   llvm::BumpPtrAllocator _allocator;
 | |
| };
 | |
| 
 | |
| template <class ELFT>
 | |
| bool ProgramHeader<ELFT>::addSegment(Segment<ELFT> *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 <class ELFT>
 | |
| void ProgramHeader<ELFT>::write(ELFWriter *writer,
 | |
|                                    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 ELFT>
 | |
| class SectionHeader : public Chunk<ELFT> {
 | |
| public:
 | |
|   typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
 | |
| 
 | |
|   SectionHeader(const ELFLinkingContext &, int32_t order);
 | |
| 
 | |
|   void appendSection(MergedSections<ELFT> *section);
 | |
| 
 | |
|   void updateSection(Section<ELFT> *section);
 | |
| 
 | |
|   static inline bool classof(const Chunk<ELFT> *c) {
 | |
|     return c->getChunkKind() == Chunk<ELFT>::Kind::SectionHeader;
 | |
|   }
 | |
| 
 | |
|   void setStringSection(StringTable<ELFT> *s) {
 | |
|     _stringSection = s;
 | |
|   }
 | |
| 
 | |
|   void write(ELFWriter *writer, 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<ELFT>::ContentType::Header; }
 | |
| 
 | |
|   inline uint64_t numHeaders() {
 | |
|     return _sectionInfo.size();
 | |
|   }
 | |
| 
 | |
| private:
 | |
|   StringTable<ELFT> *_stringSection;
 | |
|   std::vector<Elf_Shdr*>                  _sectionInfo;
 | |
|   llvm::BumpPtrAllocator                  _sectionAllocate;
 | |
| };
 | |
| 
 | |
| template <class ELFT>
 | |
| SectionHeader<ELFT>::SectionHeader(const ELFLinkingContext &context,
 | |
|                                    int32_t order)
 | |
|     : Chunk<ELFT>("shdr", Chunk<ELFT>::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>()) Elf_Shdr;
 | |
|   ::memset(nullshdr, 0, sizeof (Elf_Shdr));
 | |
|   _sectionInfo.push_back(nullshdr);
 | |
|   this->_fsize += sizeof (Elf_Shdr);
 | |
| }
 | |
| 
 | |
| template<class ELFT>
 | |
| void
 | |
| SectionHeader<ELFT>::appendSection(MergedSections<ELFT> *section) {
 | |
|   Elf_Shdr *shdr = new (_sectionAllocate.Allocate<Elf_Shdr>()) 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<class ELFT>
 | |
| void
 | |
| SectionHeader<ELFT>::updateSection(Section<ELFT> *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 <class ELFT>
 | |
| void SectionHeader<ELFT>::write(ELFWriter *writer,
 | |
|                                    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, buffer);
 | |
| }
 | |
| } // end namespace elf
 | |
| } // end namespace lld
 | |
| 
 | |
| #endif
 |