summaryrefslogtreecommitdiffstats
path: root/lld/lib/ReaderWriter/ELF/HeaderChunks.h
diff options
context:
space:
mode:
Diffstat (limited to 'lld/lib/ReaderWriter/ELF/HeaderChunks.h')
-rw-r--r--lld/lib/ReaderWriter/ELF/HeaderChunks.h309
1 files changed, 309 insertions, 0 deletions
diff --git a/lld/lib/ReaderWriter/ELF/HeaderChunks.h b/lld/lib/ReaderWriter/ELF/HeaderChunks.h
new file mode 100644
index 00000000000..e2512b55e74
--- /dev/null
+++ b/lld/lib/ReaderWriter/ELF/HeaderChunks.h
@@ -0,0 +1,309 @@
+//===- 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"
+
+/// \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 Header : public Chunk<ELFT> {
+public:
+ typedef llvm::object::Elf_Ehdr_Impl<ELFT> Elf_Ehdr;
+
+ Header(const ELFTargetInfo &);
+
+ 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>::K_Header;
+ }
+
+ void write(ELFWriter *writer, llvm::FileOutputBuffer &buffer);
+
+ void finalize() { }
+
+private:
+ Elf_Ehdr _eh;
+};
+
+template <class ELFT>
+Header<ELFT>::Header(const ELFTargetInfo &ti)
+ : Chunk<ELFT>("elfhdr", Chunk<ELFT>::K_Header, ti) {
+ 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(2);
+}
+
+template <class ELFT>
+void Header<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;
+
+ /// \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 Elf_Phdr *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 ELFTargetInfo &ti)
+ : Chunk<ELFT>("elfphdr", Chunk<ELFT>::K_ProgramHeader, ti) {
+ 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>::K_ProgramHeader;
+ }
+
+ void write(ELFWriter *writer, llvm::FileOutputBuffer &buffer);
+
+ /// \brief find a program header entry in the list of program headers
+ PhIterT findProgramHeader(uint64_t type, uint64_t flags, uint64_t flagClear) {
+ return std::find_if(_ph.begin(), _ph.end(),
+ FindPhdr(type, flags, flagClear));
+ }
+
+ PhIterT begin() {
+ return _ph.begin();
+ }
+
+ PhIterT end() {
+ return _ph.end();
+ }
+
+ void finalize() { }
+
+ int64_t entsize() {
+ return sizeof(Elf_Phdr);
+ }
+
+ int64_t numHeaders() {
+ return _ph.size();
+ }
+
+private:
+ std::vector<Elf_Phdr *> _ph;
+ PhIterT _phi;
+ llvm::BumpPtrAllocator _allocator;
+};
+
+template<class ELFT>
+bool
+ProgramHeader<ELFT>::addSegment(Segment<ELFT> *segment) {
+ Elf_Phdr *phdr = nullptr;
+ bool ret = false;
+
+ for (auto slice : segment->slices()) {
+ if (_phi == _ph.end()) {
+ phdr = new(_allocator.Allocate<Elf_Phdr>()) Elf_Phdr;
+ _ph.push_back(phdr);
+ _phi = _ph.end();
+ ret = true;
+ } else {
+ phdr = (*_phi);
+ ++_phi;
+ }
+ 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();
+ phdr->p_align = (phdr->p_type == llvm::ELF::PT_LOAD) ?
+ segment->pageSize() : slice->align2();
+ }
+ this->_fsize = fileSize();
+ this->_msize = this->_fsize;
+
+ return ret;
+}
+
+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 ELFTargetInfo &, 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>::K_SectionHeader;
+ }
+
+ void setStringSection(StringTable<ELFT> *s) {
+ _stringSection = s;
+ }
+
+ void write(ELFWriter *writer, llvm::FileOutputBuffer &buffer);
+
+ void finalize() { }
+
+ inline uint16_t fileSize() {
+ return sizeof(Elf_Shdr) * _sectionInfo.size();
+ }
+
+ inline int64_t entsize() {
+ return sizeof(Elf_Shdr);
+ }
+
+ inline int64_t numHeaders() {
+ return _sectionInfo.size();
+ }
+
+private:
+ StringTable<ELFT> *_stringSection;
+ std::vector<Elf_Shdr*> _sectionInfo;
+ llvm::BumpPtrAllocator _sectionAllocate;
+};
+
+template <class ELFT>
+SectionHeader<ELFT>::SectionHeader(const ELFTargetInfo &ti, int32_t order)
+ : Chunk<ELFT>("shdr", Chunk<ELFT>::K_SectionHeader, ti) {
+ 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();
+ shdr->sh_size = section->memSize();
+ 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->type();
+ shdr->sh_flags = section->flags();
+ shdr->sh_offset = section->fileOffset();
+ shdr->sh_addr = section->virtualAddr();
+ 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();
+}
+
+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
OpenPOWER on IntegriCloud