//////////////////////////////////////////////////////////////////////////////// // // The University of Illinois/NCSA // Open Source License (NCSA) // // Copyright (c) 2014-2020, Advanced Micro Devices, Inc. All rights reserved. // // Developed by: // // AMD Research and AMD HSA Software Development // // Advanced Micro Devices, Inc. // // www.amd.com // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal with the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimers. // - Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimers in // the documentation and/or other materials provided with the distribution. // - Neither the names of Advanced Micro Devices, Inc, // nor the names of its contributors may be used to endorse or promote // products derived from this Software without specific prior written // permission. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS WITH THE SOFTWARE. // //////////////////////////////////////////////////////////////////////////////// #include "core/inc/amd_elf_image.hpp" #include "amd_hsa_code_util.hpp" #include #include #include #include #include #include #include #include #include #ifdef _WIN32 #include #define alignof __alignof #endif // _WIN32 #include #ifndef _WIN32 #define _open open #define _close close #define _tempnam tempnam #include #include #endif #if defined(USE_MEMFILE) #include "memfile.h" #define OpenTemp(f) mem_open(NULL, 0, 0) #define CloseTemp(f) mem_close(f) #define _read(f, b, l) mem_read((f), (b), (l)) #define _write(f, b, l) mem_write((f), (b), (l)) #define _lseek(f, l, w) mem_lseek((f), (l), (w)) #define _ftruncate(f, l) mem_ftruncate((f), (size_t)(l)) #define sendfile(o, i, p, s) mem_sendfile((o), (i), (p), (s)) #else // USE_MEMFILE #define OpenTemp(f) amd::hsa::OpenTempFile(f); #define CloseTemp(f) amd::hsa::CloseTempFile(f); #ifndef _WIN32 #define _read read #define _write write #define _lseek lseek #define _ftruncate ftruncate #include #else #define _ftruncate _chsize #endif // !_WIN32 #endif // !USE_MEMFILE #if !defined(BSD_LIBELF) #define elf_setshstrndx elfx_update_shstrndx #endif #define NOTE_RECORD_ALIGNMENT 4 using rocr::amd::hsa::alignUp; namespace rocr { namespace amd { namespace elf { class FileImage { public: FileImage(); ~FileImage(); bool create(); bool readFrom(const std::string& filename); bool copyFrom(const void* data, size_t size); bool writeTo(const std::string& filename); bool copyTo(void** buffer, size_t* size = 0); bool copyTo(void* buffer, size_t size); size_t getSize(); std::string output() { return out.str(); } int fd() { return d; } private: int d; std::ostringstream out; bool error(const char* msg); bool perror(const char *msg); std::string werror(); }; FileImage::FileImage() : d(-1) { } FileImage::~FileImage() { if (d != -1) { CloseTemp(d); } } bool FileImage::error(const char* msg) { out << "Error: " << msg << std::endl; return false; } bool FileImage::perror(const char* msg) { out << "Error: " << msg << ": " << strerror(errno) << std::endl; return false; } #ifdef _WIN32 std::string FileImage::werror() { LPVOID lpMsgBuf; DWORD dw = GetLastError(); FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL); std::string result((LPTSTR)lpMsgBuf); LocalFree(lpMsgBuf); return result; } #endif // _WIN32 bool FileImage::create() { d = OpenTemp("amdelf"); if (d == -1) { return error("Failed to open temporary file for elf image"); } return true; } bool FileImage::readFrom(const std::string& filename) { #ifdef _WIN32 std::unique_ptr buffer(new char[32 * 1024 * 1024]); HANDLE in = CreateFile(filename.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (in == INVALID_HANDLE_VALUE) { out << "Failed to open " << filename << ": " << werror() << std::endl; return false; } DWORD read; unsigned write; int written; do { if (!ReadFile(in, buffer.get(), sizeof(buffer), &read, NULL)) { out << "Failed to read " << filename << ": " << werror() << std::endl; CloseHandle(in); return false; } if (read > 0) { write = read; do { written = _write(d, buffer.get(), write); if (written < 0) { out << "Failed to write image file: " << werror() << std::endl; CloseHandle(in); } write -= written; } while (write > 0); } } while (read > 0); if (_lseek(d, 0L, SEEK_SET) < 0) { return perror("lseek(0) failed"); } CloseHandle(in); return true; #else // _WIN32 int in = _open(filename.c_str(), O_RDONLY); if (in < 0) { return perror("open failed"); } if (_lseek(in, 0L, SEEK_END) < 0) { _close(in); return perror("lseek failed"); } off_t size; if ((size = _lseek(in, 0L, SEEK_CUR)) < 0) { _close(in); return perror("lseek(2) failed"); } if (_lseek(in, 0L, SEEK_SET) < 0) { _close(in); return perror("lseek(3) failed"); } if (_lseek(d, 0L, SEEK_SET) < 0) { return perror("lseek(3) failed"); } ssize_t written; do { written = sendfile(d, in, NULL, size); if (written < 0) { _close(in); return perror("sendfile failed"); } size -= written; } while (size > 0); _close(in); if (_lseek(d, 0L, SEEK_SET) < 0) { return perror("lseek(0) failed"); } return true; #endif // _WIN32 } bool FileImage::copyFrom(const void* data, size_t size) { assert(d != -1); if (_lseek(d, 0L, SEEK_SET) < 0) { return perror("lseek failed"); } if (_ftruncate(d, 0) < 0) { return perror("ftruncate failed"); } int written, offset = 0; while (size > 0) { written = _write(d, (const char*) data + offset, size); if (written < 0) { return perror("write failed"); } size -= written; offset += written; } if (_lseek(d, 0L, SEEK_SET) < 0) { return perror("lseek failed"); } return true; } size_t FileImage::getSize() { assert(d != -1); if (_lseek(d, 0L, SEEK_END) < 0) { return perror("lseek failed"); } long seek = 0; if ((seek = _lseek(d, 0L, SEEK_CUR)) < 0) { return perror("lseek(2) failed"); } if (_lseek(d, 0L, SEEK_SET) < 0) { return perror("lseek(3) failed"); } return seek; } bool FileImage::copyTo(void** buffer, size_t* size) { size_t size1 = getSize(); void* buffer1 = malloc(size1); if (_read(d, buffer1, size1) < 0) { free(buffer1); return perror("read failed"); } *buffer = buffer1; if (size) { *size = size1; } return true; } bool FileImage::copyTo(void* buffer, size_t size) { size_t size1 = getSize(); if (size < size1) { return error("Buffer size is not enough"); } if (_read(d, buffer, size1) < 0) { return perror("read failed"); } return true; } bool FileImage::writeTo(const std::string& filename) { bool res = false; size_t size = 0; void *buffer = nullptr; if (copyTo(&buffer, &size)) { res = true; std::ofstream out(filename.c_str(), std::ios::binary); out.write((char*)buffer, size); } free(buffer); return res; } class Buffer { public: typedef unsigned char byte_type; typedef size_t size_type; Buffer(); Buffer(const byte_type *src, size_type size, size_type align = 0); virtual ~Buffer(); const byte_type* raw() const { return this->isConst() ? ptr_ : data_.data(); } size_type align() const { return align_; } size_type size() const { return this->isConst() ? size_ : data_.size(); } bool isConst() const { return 0 != size_; } bool isEmpty() { return size() == 0; } bool hasRaw(const byte_type *src) const { return (src >= this->raw()) && (src < this->raw() + this->size()); } template bool has(const T *src) const { return this->hasRaw((const byte_type*)src); } bool has(size_type offset) const { return offset < this->size(); } template size_type getOffset(const T *src) const { return this->getRawOffset((const byte_type*)src); } template T get(size_type offset) const { return (T)this->getRaw(offset); } size_type addString(const std::string &str, size_type align = 0); size_type addStringLength(const std::string &str, size_type align = 0); size_type nextOffset(size_type align) const { return alignUp(this->size(), align); } template size_type add(const T *src, size_type size, size_type align) { return this->addRaw((const byte_type*)src, size, align); } template size_type add(const T &src, size_type align = 0) { return this->addRaw((const byte_type*)&src, sizeof(T), align == 0 ? alignof(T) : align); } size_type align(size_type align); template size_type reserve() { Buffer::size_type offset = this->align(alignof(T)); data_.insert(data_.end(), sizeof(T), 0x0); return offset; } private: size_type getRawOffset(const byte_type *src) const; const byte_type* getRaw(size_type offset) const; size_type addRaw(const byte_type *src, size_type size, size_type align); std::vector data_; const byte_type *ptr_; size_type size_; size_type align_; }; Buffer::Buffer() : ptr_(nullptr) , size_(0) , align_(0) { } Buffer::Buffer(const Buffer::byte_type *src, Buffer::size_type size, Buffer::size_type align) : ptr_(src) , size_(size) , align_(align) { } Buffer::~Buffer() { } Buffer::size_type Buffer::getRawOffset(const Buffer::byte_type *src) const { assert(this->has(src)); return src - this->raw(); } const Buffer::byte_type* Buffer::getRaw(Buffer::size_type offset) const { assert(this->has(offset)); return this->raw() + offset; } Buffer::size_type Buffer::addRaw(const Buffer::byte_type *src, Buffer::size_type size, Buffer::size_type align) { assert(!this->isConst()); assert(nullptr != src); assert(0 != size); assert(0 != align); Buffer::size_type offset = this->align(align); data_.insert(data_.end(), src, src + size); return offset; } Buffer::size_type Buffer::addString(const std::string &str, size_type align) { return this->add(str.c_str(), str.length() + 1, align == 0 ? alignof(char) : align); } Buffer::size_type Buffer::addStringLength(const std::string &str, size_type align) { return this->add((uint32_t)(str.length() + 1), align == 0 ? alignof(uint32_t) : align); } Buffer::size_type Buffer::align(Buffer::size_type align) { assert(!this->isConst()); assert(0 != align); Buffer::size_type offset = alignUp(this->size(), align); align_ = (std::max)(align_, align); data_.insert(data_.end(), offset - this->size(), 0x0); return offset; } class GElfImage; class GElfSegment; class GElfSection : public virtual Section { public: GElfSection(GElfImage* elf); bool push(const char* name, uint32_t shtype, uint64_t shflags, uint16_t shlink, uint32_t info, uint32_t align, uint64_t entsize = 0); bool pull0(); bool pull(uint16_t ndx); virtual bool pullData() { return true; } bool push(); uint16_t getSectionIndex() const override; uint32_t type() const override { return hdr.sh_type; } std::string Name() const override; uint64_t offset() const override { return hdr.sh_offset; } uint64_t addr() const override { return hdr.sh_addr; } bool updateAddr(uint64_t addr) override; uint64_t addralign() const override { return data0.size() == 0 ? data.align() : data0.align(); } uint64_t flags() const override { return hdr.sh_flags; } uint64_t size() const override { return data0.size() == 0 ? data.size() : data0.size(); } uint64_t nextDataOffset(uint64_t align) const override; uint64_t addData(const void *src, uint64_t size, uint64_t align) override; bool getData(uint64_t offset, void* dest, uint64_t size) override; bool hasRelocationSection() const override { return reloc_sec != 0; } RelocationSection* relocationSection(SymbolTable* symtab = 0) override; Segment* segment() override { return seg; } RelocationSection* asRelocationSection() override { return 0; } bool setMemSize(uint64_t s) override { memsize_ = s; return true; } uint64_t memSize() const override { return memsize_ ? memsize_ : size(); } bool setAlign(uint64_t a) override { align_ = a; return true; } uint64_t memAlign() const override { return align_ ? align_ : addralign(); } protected: GElfImage* elf; Segment* seg; GElf_Shdr hdr; Buffer data0, data; uint64_t memsize_; uint64_t align_; RelocationSection *reloc_sec; size_t ndxscn; friend class GElfSymbol; friend class GElfSegment; friend class GElfImage; }; class GElfSegment : public Segment { public: GElfSegment(GElfImage* elf, uint16_t index); GElfSegment(GElfImage* elf, uint16_t index, uint32_t type, uint32_t flags, uint64_t paddr = 0); bool push(uint64_t vaddr); bool pull(); uint64_t type() const override { return phdr.p_type; } uint64_t memSize() const override { return phdr.p_memsz; } uint64_t align() const override { return phdr.p_align; } uint64_t imageSize() const override { return phdr.p_filesz; } uint64_t vaddr() const override { return phdr.p_vaddr; } uint64_t flags() const override { return phdr.p_flags; } uint64_t offset() const override { return phdr.p_offset; } const char* data() const override; uint16_t getSegmentIndex() override; bool updateAddSection(Section *section) override; private: GElfImage* elf; uint16_t index; GElf_Phdr phdr; std::vector sections; }; class GElfStringTable : public GElfSection, public StringTable { public: GElfStringTable(GElfImage* elf); bool push(const char* name, uint32_t shtype, uint64_t shflags); bool pullData() override; const char* addString(const std::string& s) override; size_t addString1(const std::string& s) override; const char* getString(size_t ndx) override; size_t getStringIndex(const char* name) override; uint16_t getSectionIndex() const override { return GElfSection::getSectionIndex(); } uint32_t type() const override { return GElfSection::type(); } std::string Name() const override { return GElfSection::Name(); } uint64_t addr() const override { return GElfSection::addr(); } uint64_t offset() const override { return GElfSection::offset(); } bool updateAddr(uint64_t addr) override { return GElfSection::updateAddr(addr); } uint64_t addralign() const override { return GElfSection::addralign(); } uint64_t flags() const override { return GElfSection::flags(); } uint64_t size() const override { return GElfSection::size(); } Segment* segment() override { return GElfSection::segment(); } uint64_t nextDataOffset(uint64_t align) const override { return GElfSection::nextDataOffset(align); } uint64_t addData(const void *src, uint64_t size, uint64_t align) override { return GElfSection::addData(src, size, align); } bool getData(uint64_t offset, void* dest, uint64_t size) override { return GElfSection::getData(offset, dest, size); } bool hasRelocationSection() const override { return GElfSection::hasRelocationSection(); } RelocationSection* relocationSection(SymbolTable* symtab) override { return GElfSection::relocationSection(); } RelocationSection* asRelocationSection() override { return 0; } uint64_t memSize() const override { return GElfSection::memSize(); } bool setMemSize(uint64_t s) override { return GElfSection::setMemSize(s); } uint64_t memAlign() const override { return GElfSection::memAlign(); } bool setAlign(uint64_t a) override { return GElfSection::setAlign(a); } }; class GElfSymbolTable; class GElfSymbol : public Symbol { public: GElfSymbol(GElfSymbolTable* symtab, Buffer &data, size_t index); bool push(const std::string& name, uint64_t value, uint64_t size, unsigned char type, unsigned char binding, uint16_t shndx, unsigned char other); uint32_t index() override { return eindex / sizeof(GElf_Rela); } uint32_t type() override { return GELF_ST_TYPE(Sym()->st_info); } uint32_t binding() override { return GELF_ST_BIND(Sym()->st_info); } uint64_t size() override { return Sym()->st_size; } uint64_t value() override { return Sym()->st_value; } unsigned char other() override { return Sym()->st_other; } std::string name() override; Section* section() override; void setValue(uint64_t value) override { Sym()->st_value = value; } void setSize(uint64_t size) override { Sym()->st_size = size; } private: GElf_Sym* Sym() { return edata.get(eindex); } GElfSymbolTable* symtab; Buffer &edata; size_t eindex; friend class GElfSymbolTable; }; class GElfSymbolTable : public GElfSection, public SymbolTable { private: Symbol* addSymbolInternal(Section* section, const std::string& name, uint64_t value, uint64_t size, unsigned char type, unsigned char binding, unsigned char other = 0); GElfStringTable* strtab; std::vector> symbols; friend class GElfSymbol; public: GElfSymbolTable(GElfImage* elf); bool push(const char* name, GElfStringTable* strtab); bool pullData() override; uint16_t getSectionIndex() const override { return GElfSection::getSectionIndex(); } uint32_t type() const override { return GElfSection::type(); } std::string Name() const override { return GElfSection::Name(); } uint64_t offset() const override { return GElfSection::offset(); } uint64_t addr() const override { return GElfSection::addr(); } bool updateAddr(uint64_t addr) override { return GElfSection::updateAddr(addr); } uint64_t addralign() const override { return GElfSection::addralign(); } uint64_t flags() const override { return GElfSection::flags(); } uint64_t size() const override { return GElfSection::size(); } Segment* segment() override { return GElfSection::segment(); } uint64_t nextDataOffset(uint64_t align) const override { return GElfSection::nextDataOffset(align); } uint64_t addData(const void *src, uint64_t size, uint64_t align) override { return GElfSection::addData(src, size, align); } bool getData(uint64_t offset, void* dest, uint64_t size) override { return GElfSection::getData(offset, dest, size); } bool hasRelocationSection() const override { return GElfSection::hasRelocationSection(); } RelocationSection* relocationSection(SymbolTable* symtab) override { return GElfSection::relocationSection(); } Symbol* addSymbol(Section* section, const std::string& name, uint64_t value, uint64_t size, unsigned char type, unsigned char binding, unsigned char other = 0) override; size_t symbolCount() override; Symbol* symbol(size_t i) override; RelocationSection* asRelocationSection() override { return 0; } uint64_t memSize() const override { return GElfSection::memSize(); } bool setMemSize(uint64_t s) override { return GElfSection::setMemSize(s); } uint64_t memAlign() const override { return GElfSection::memAlign(); } bool setAlign(uint64_t a) override { return GElfSection::setAlign(a); } }; class GElfNoteSection : public GElfSection, public NoteSection { public: GElfNoteSection(GElfImage* elf); bool push(const std::string& name); uint16_t getSectionIndex() const override { return GElfSection::getSectionIndex(); } uint32_t type() const override { return GElfSection::type(); } std::string Name() const override { return GElfSection::Name(); } uint64_t addr() const override { return GElfSection::addr(); } bool updateAddr(uint64_t addr) override { return GElfSection::updateAddr(addr); } uint64_t offset() const override { return GElfSection::offset(); } uint64_t addralign() const override { return GElfSection::addralign(); } uint64_t flags() const override { return GElfSection::flags(); } uint64_t size() const override { return GElfSection::size(); } Segment* segment() override { return GElfSection::segment(); } uint64_t nextDataOffset(uint64_t align) const override { return GElfSection::nextDataOffset(align); } uint64_t addData(const void *src, uint64_t size, uint64_t align) override { return GElfSection::addData(src, size, align); } bool getData(uint64_t offset, void* dest, uint64_t size) override { return GElfSection::getData(offset, dest, size); } bool hasRelocationSection() const override { return GElfSection::hasRelocationSection(); } RelocationSection* relocationSection(SymbolTable* symtab) override { return GElfSection::relocationSection(); } bool addNote(const std::string& name, uint32_t type, const void* desc, uint32_t desc_size) override; bool getNote(const std::string& name, uint32_t type, void** desc, uint32_t* desc_size) override; RelocationSection* asRelocationSection() override { return 0; } uint64_t memSize() const override { return GElfSection::memSize(); } bool setMemSize(uint64_t s) override { return GElfSection::setMemSize(s); } uint64_t memAlign() const override { return GElfSection::memAlign(); } bool setAlign(uint64_t a) override { return GElfSection::setAlign(a); } }; class GElfRelocationSection; class GElfRelocation : public Relocation { private: GElf_Rela *Rela() { return edata.get(eindex); } GElfRelocationSection* rsection; Buffer &edata; size_t eindex; public: GElfRelocation(GElfRelocationSection* rsection_, Buffer &edata_, size_t eindex_) : rsection(rsection_), edata(edata_), eindex(eindex_) { } bool push(uint32_t type, Symbol* symbol, uint64_t offset, int64_t addend); RelocationSection* section() override; uint32_t type() override { return GELF_R_TYPE(Rela()->r_info); } uint32_t symbolIndex() override { return GELF_R_SYM(Rela()->r_info); } Symbol* symbol() override; uint64_t offset() override { return Rela()->r_offset; } int64_t addend() override { return Rela()->r_addend; } }; class GElfRelocationSection : public GElfSection, public RelocationSection { private: Section* section; GElfSymbolTable* symtab; std::vector> relocations; public: GElfRelocationSection(GElfImage* elf, Section* targetSection = 0, GElfSymbolTable* symtab_ = 0); bool push(const std::string& name); bool pullData() override; uint16_t getSectionIndex() const override { return GElfSection::getSectionIndex(); } uint32_t type() const override { return GElfSection::type(); } std::string Name() const override { return GElfSection::Name(); } uint64_t addr() const override { return GElfSection::addr(); } uint64_t offset() const override { return GElfSection::offset(); } bool updateAddr(uint64_t addr) override { return GElfSection::updateAddr(addr); } uint64_t addralign() const override { return GElfSection::addralign(); } uint64_t flags() const override { return GElfSection::flags(); } uint64_t size() const override { return GElfSection::size(); } Segment* segment() override { return GElfSection::segment(); } uint64_t nextDataOffset(uint64_t align) const override { return GElfSection::nextDataOffset(align); } uint64_t addData(const void *src, uint64_t size, uint64_t align) override { return GElfSection::addData(src, size, align); } bool getData(uint64_t offset, void* dest, uint64_t size) override { return GElfSection::getData(offset, dest, size); } bool hasRelocationSection() const override { return GElfSection::hasRelocationSection(); } RelocationSection* relocationSection(SymbolTable* symtab) override { return GElfSection::relocationSection(); } RelocationSection* asRelocationSection() override { return this; } size_t relocationCount() const override { return relocations.size(); } Relocation* relocation(size_t i) override { return relocations[i].get(); } Relocation* addRelocation(uint32_t type, Symbol* symbol, uint64_t offset, int64_t addend) override; Section* targetSection() override { return section; } uint64_t memSize() const override { return GElfSection::memSize(); } bool setMemSize(uint64_t s) override { return GElfSection::setMemSize(s); } uint64_t memAlign() const override { return GElfSection::memAlign(); } bool setAlign(uint64_t a) override { return GElfSection::setAlign(a); } friend class GElfRelocation; }; class GElfImage : public Image { public: GElfImage(int elfclass); ~GElfImage(); bool initNew(uint16_t machine, uint16_t type, uint8_t os_abi = 0, uint8_t abi_version = 0, uint32_t e_flags = 0) override; bool loadFromFile(const std::string& filename) override; bool saveToFile(const std::string& filename) override; bool initFromBuffer(const void* buffer, size_t size) override; bool initAsBuffer(const void* buffer, size_t size) override; bool close(); bool writeTo(const std::string& filename) override; bool copyToBuffer(void** buf, size_t* size = 0) override; bool copyToBuffer(void* buf, size_t size) override; const char* data() override { assert(buffer); return buffer; } uint64_t size() override; bool push(); bool Freeze() override; bool Validate() override; uint16_t Machine() override { return ehdr.e_machine; } uint16_t Type() override { return ehdr.e_type; } uint32_t EFlags() override { return ehdr.e_flags; } uint32_t ABIVersion() override { return (uint32_t)(ehdr.e_ident[EI_ABIVERSION]); } uint32_t EClass() override { return (uint32_t)(ehdr.e_ident[EI_CLASS]); } uint32_t OsAbi() override { return (uint32_t)(ehdr.e_ident[EI_OSABI]); } GElfStringTable* shstrtab() override; GElfStringTable* strtab() override; GElfSymbolTable* getReferencedSymbolTable(uint16_t index) { return static_cast(section(index)); } GElfSymbolTable* getSymtab(uint16_t index) override { if (section(index)->type() == SHT_SYMTAB) return static_cast(section(index)); return nullptr; } GElfSymbolTable* getDynsym(uint16_t index) override { if (section(index)->type() == SHT_DYNSYM) return static_cast(section(index)); return nullptr; } GElfSymbolTable* getSymbolTable() override; GElfSymbolTable* getSymbolTable(uint16_t index) override { const char *UseDynsym = getenv("LOADER_USE_DYNSYM"); if (UseDynsym && std::strncmp(UseDynsym, "0", 1) != 0) return getDynsym(index); return getSymtab(index); } GElfStringTable* addStringTable(const std::string& name) override; GElfStringTable* getStringTable(uint16_t index) override; GElfSymbolTable* addSymbolTable(const std::string& name, StringTable* stab = 0) override; GElfSymbolTable* symtab() override; GElfSymbolTable* dynsym() override; GElfSegment* segment(size_t i) override { return segments[i].get(); } Segment* segmentByVAddr(uint64_t vaddr) override; size_t sectionCount() override { return sections.size(); } GElfSection* section(size_t i) override { return sections[i].get(); } Section* sectionByVAddr(uint64_t vaddr) override; uint16_t machine() const; uint16_t etype() const; int eclass() const { return elfclass; } bool elfError(const char* msg); GElfNoteSection* note() override; GElfNoteSection* addNoteSection(const std::string& name) override; size_t segmentCount() override { return segments.size(); } Segment* initSegment(uint32_t type, uint32_t flags, uint64_t paddr = 0) override; bool addSegments() override; Section* addSection(const std::string &name, uint32_t type, uint64_t flags = 0, uint64_t entsize = 0, Segment* segment = 0) override; RelocationSection* addRelocationSection(Section* sec, SymbolTable* symtab); RelocationSection* relocationSection(Section* sec, SymbolTable* symtab = 0) override; private: bool frozen; int elfclass; FileImage img; const char* buffer; size_t bufferSize; Elf* e; GElf_Ehdr ehdr; GElfStringTable* shstrtabSection; GElfStringTable* strtabSection; GElfSymbolTable* symtabSection; GElfSymbolTable* dynsymSection; GElfNoteSection* noteSection; std::vector> segments; std::vector> sections; bool imgError(); const char *elfError(); bool elfBegin(Elf_Cmd cmd); bool elfEnd(); bool push0(); bool pullElf(); friend class GElfSection; friend class GElfSymbolTable; friend class GElfNoteSection; friend class GElfRelocationSection; friend class GElfSegment; friend class GElfSymbol; }; GElfSegment::GElfSegment(GElfImage* elf_, uint16_t index_) : elf(elf_), index(index_) { memset(&phdr, 0, sizeof(phdr)); } GElfSegment::GElfSegment(GElfImage* elf_, uint16_t index_, uint32_t type, uint32_t flags, uint64_t paddr) : elf(elf_), index(index_) { memset(&phdr, 0, sizeof(phdr)); phdr.p_type = type; phdr.p_flags = flags; phdr.p_paddr = paddr; } const char* GElfSegment::data() const { return (const char*) elf->data() + phdr.p_offset; } bool GElfImage::Freeze() { assert(!frozen); if (!push()) { return false; } frozen = true; return true; } bool GElfImage::Validate() { if (ELFMAG0 != ehdr.e_ident[EI_MAG0] || ELFMAG1 != ehdr.e_ident[EI_MAG1] || ELFMAG2 != ehdr.e_ident[EI_MAG2] || ELFMAG3 != ehdr.e_ident[EI_MAG3]) { out << "Invalid ELF magic" << std::endl; return false; } if (EV_CURRENT != ehdr.e_version) { out << "Invalid ELF version" << std::endl; return false; } return true; } bool GElfSegment::push(uint64_t vaddr) { phdr.p_align = 0; phdr.p_offset = 0; if (!sections.empty()) { phdr.p_offset = sections[0]->offset(); } for (Section* section : sections) { phdr.p_align = (std::max)(phdr.p_align, section->memAlign()); } phdr.p_vaddr = alignUp(vaddr, (std::max)(phdr.p_align, (uint64_t) 1)); phdr.p_filesz = 0; phdr.p_memsz = 0; for (Section* section : sections) { phdr.p_memsz = alignUp(phdr.p_memsz, (std::max)(section->memAlign(), (uint64_t) 1)); phdr.p_filesz = alignUp(phdr.p_filesz, (std::max)(section->memAlign(), (uint64_t) 1)); if (!section->updateAddr(phdr.p_vaddr + phdr.p_memsz)) { return false; } phdr.p_filesz += (section->type() == SHT_NOBITS) ? 0 : section->size(); phdr.p_memsz += section->memSize(); } if (!gelf_update_phdr(elf->e, index, &phdr)) { return elf->elfError("gelf_update_phdr failed"); } return true; } bool GElfSegment::pull() { if (!gelf_getphdr(elf->e, index, &phdr)) { return elf->elfError("gelf_getphdr failed"); } return true; } uint16_t GElfSegment::getSegmentIndex() { return index; } bool GElfSegment::updateAddSection(Section *section) { sections.push_back(section); return true; } GElfSection::GElfSection(GElfImage* elf_) : elf(elf_), seg(nullptr), hdr{}, memsize_(0), align_(0), reloc_sec(nullptr), ndxscn(0) { } uint16_t GElfSection::getSectionIndex() const { return (uint16_t)ndxscn; } std::string GElfSection::Name() const { return std::string(elf->shstrtab()->getString(hdr.sh_name)); } bool GElfSection::updateAddr(uint64_t addr) { Elf_Scn *scn = elf_getscn(elf->e, ndxscn); assert(scn); if (!gelf_getshdr(scn, &hdr)) { return elf->elfError("gelf_get_shdr failed"); } hdr.sh_addr = addr; if (!gelf_update_shdr(scn, &hdr)) { return elf->elfError("gelf_update_shdr failed"); } return true; } bool GElfSection::push(const char* name, uint32_t shtype, uint64_t shflags, uint16_t shlink, uint32_t info, uint32_t align, uint64_t entsize) { Elf_Scn *scn = elf_newscn(elf->e); if (!scn) { return false; } ndxscn = elf_ndxscn(scn); if (!gelf_getshdr(scn, &hdr)) { return elf->elfError("gelf_get_shdr failed"); } align = (std::max)(align, (uint32_t) 8); hdr.sh_name = elf->shstrtab()->addString1(name); hdr.sh_type = shtype; hdr.sh_flags = shflags; hdr.sh_link = shlink; hdr.sh_addr = 0; hdr.sh_info = info; hdr.sh_addralign = align; hdr.sh_entsize = entsize; if (!gelf_update_shdr(scn, &hdr)) { return elf->elfError("gelf_update_shdr failed"); } return true; } bool GElfSection::pull0() { Elf_Scn *scn = elf_getscn(elf->e, ndxscn); if (!scn) { return false; } if (!gelf_getshdr(scn, &hdr)) { return elf->elfError("gelf_get_shdr failed"); } return true; } bool GElfSection::pull(uint16_t ndx) { ndxscn = (size_t) ndx; if (!pull0()) { return false; } Elf_Scn *scn = elf_getscn(elf->e, ndx); if (!scn) { return false; } Elf_Data *edata0 = elf_getdata(scn, NULL); if (edata0) { data0 = Buffer((const Buffer::byte_type*)edata0->d_buf, edata0->d_size, edata0->d_align); } seg = elf->segmentByVAddr(hdr.sh_addr); return true; } bool GElfSection::push() { Elf_Scn *scn = elf_getscn(elf->e, ndxscn); assert(scn); Elf_Data *edata = nullptr; edata = elf_newdata(scn); if (!edata) { return elf->elfError("elf_newdata failed"); } if (hdr.sh_type == SHT_NOBITS) { edata->d_buf = 0; edata->d_size = memsize_; if (align_ != 0) { edata->d_align = align_; } } else { edata->d_buf = (void*)data.raw(); edata->d_size = data.size(); if (data.align() != 0) { edata->d_align = data.align(); } } edata->d_align = (std::max)(edata->d_align, (uint64_t) 8); switch (hdr.sh_type) { case SHT_RELA: edata->d_type = ELF_T_RELA; break; case SHT_SYMTAB: edata->d_type = ELF_T_SYM; break; default: edata->d_type = ELF_T_BYTE; break; } edata->d_version = EV_CURRENT; if (!gelf_getshdr(scn, &hdr)) { return elf->elfError("gelf_get_shdr failed"); } hdr.sh_size = edata->d_size; hdr.sh_addralign = edata->d_align; if (!gelf_update_shdr(scn, &hdr)) { return elf->elfError("gelf_update_shdr failed"); } return true; } uint64_t GElfSection::nextDataOffset(uint64_t align) const { return data.nextOffset(align); } uint64_t GElfSection::addData(const void *src, uint64_t size, uint64_t align) { return data.add(src, size, align); } bool GElfSection::getData(uint64_t offset, void* dest, uint64_t size) { Elf_Data* edata = 0; uint64_t coffset = 0; uint64_t csize = 0; Elf_Scn *scn = elf_getscn(elf->e, ndxscn); assert(scn); if ((edata = elf_getdata(scn, edata)) != 0) { if (coffset <= offset && offset <= coffset + edata->d_size) { csize = (std::min)(size, edata->d_size - offset); memcpy(dest, (const char*) edata->d_buf + offset - coffset, csize); dest = (char*) dest + csize; size -= csize; if (!size) { return true; } } } return false; } RelocationSection* GElfSection::relocationSection(SymbolTable* symtab) { if (!reloc_sec) { reloc_sec = elf->addRelocationSection(this, symtab); } return reloc_sec; } GElfStringTable::GElfStringTable(GElfImage* elf) : GElfSection(elf) { } bool GElfStringTable::push(const char* name, uint32_t shtype, uint64_t shflags) { if (!GElfSection::push(name, shtype, shflags, SHN_UNDEF, 0, 0)) { return false; } return true; } bool GElfStringTable::pullData() { return true; } const char* GElfStringTable::addString(const std::string& s) { if (data0.size() == 0 && data.size() == 0) { data.add('\0'); } return data.get(data.addString(s)); } size_t GElfStringTable::addString1(const std::string& s) { if (data0.size() == 0 && data.size() == 0) { data.add('\0'); } return data.addString(s); } const char* GElfStringTable::getString(size_t ndx) { if (data0.has(ndx)) { return data0.get(ndx); } else if (data.has(ndx)) { return data.get(ndx); } return nullptr; } size_t GElfStringTable::getStringIndex(const char* s) { if (data0.has(s)) { return data0.getOffset(s); } else if (data.has(s)) { return data.getOffset(s); } else { assert(false); return 0; } } GElfSymbol::GElfSymbol(GElfSymbolTable* symtab_, Buffer &data_, size_t index_) : symtab(symtab_), edata(data_), eindex(index_) { } Section* GElfSymbol::section() { if (Sym()->st_shndx != SHN_UNDEF) { return symtab->elf->section(Sym()->st_shndx); } return 0; } bool GElfSymbol::push(const std::string& name, uint64_t value, uint64_t size, unsigned char type, unsigned char binding, uint16_t shndx, unsigned char other) { Sym()->st_name = symtab->strtab->addString1(name.c_str()); Sym()->st_value = value; Sym()->st_size = size; Sym()->st_info = GELF_ST_INFO(binding, type); Sym()->st_shndx = shndx; Sym()->st_other = other; return true; } std::string GElfSymbol::name() { return symtab->strtab->getString(Sym()->st_name); } GElfSymbolTable::GElfSymbolTable(GElfImage* elf) : GElfSection(elf), strtab(0) { } bool GElfSymbolTable::push(const char* name, GElfStringTable* strtab) { if (!strtab) { strtab = elf->strtab(); } this->strtab = strtab; if (!GElfSection::push(name, SHT_SYMTAB, 0, strtab->getSectionIndex(), 0, 0, sizeof(Elf64_Sym))) { return false; } return true; } bool GElfSymbolTable::pullData() { strtab = elf->getStringTable(hdr.sh_link); for (size_t i = 0; i < data0.size() / sizeof(GElf_Sym); ++i) { symbols.push_back(std::unique_ptr(new GElfSymbol(this, data0, i * sizeof(GElf_Sym)))); } return true; } Symbol* GElfSymbolTable::addSymbolInternal(Section* section, const std::string& name, uint64_t value, uint64_t size, unsigned char type, unsigned char binding, unsigned char other) { GElfSymbol *sym = new (std::nothrow) GElfSymbol(this, data, data.reserve()); uint16_t shndx = section ? section->getSectionIndex() : (uint16_t) SHN_UNDEF; if (!sym->push(name, value, size, type, binding, shndx, other)) { delete sym; return nullptr; } symbols.push_back(std::unique_ptr(sym)); return sym; } Symbol* GElfSymbolTable::addSymbol(Section* section, const std::string& name, uint64_t value, uint64_t size, unsigned char type, unsigned char binding, unsigned char other) { if (symbols.size() == 0) { this->addSymbolInternal(nullptr, "", 0, 0, 0, 0, 0); } return this->addSymbolInternal(section, name, value, size, type, binding, other); } size_t GElfSymbolTable::symbolCount() { return symbols.size(); } Symbol* GElfSymbolTable::symbol(size_t i) { return symbols[i].get(); } GElfNoteSection::GElfNoteSection(GElfImage* elf) : GElfSection(elf) { } bool GElfNoteSection::push(const std::string& name) { return GElfSection::push(name.c_str(), SHT_NOTE, 0, 0, 0, 8); } bool GElfNoteSection::addNote(const std::string& name, uint32_t type, const void* desc, uint32_t desc_size) { data.addStringLength(name, NOTE_RECORD_ALIGNMENT); data.add(desc_size, NOTE_RECORD_ALIGNMENT); data.add(type, NOTE_RECORD_ALIGNMENT); data.addString(name, NOTE_RECORD_ALIGNMENT); data.align(NOTE_RECORD_ALIGNMENT); if (desc_size > 0) { assert(desc); data.add(desc, desc_size, NOTE_RECORD_ALIGNMENT); data.align(NOTE_RECORD_ALIGNMENT); } return true; } bool GElfNoteSection::getNote(const std::string& name, uint32_t type, void** desc, uint32_t* desc_size) { Elf_Data* data = 0; Elf_Scn *scn = elf_getscn(elf->e, ndxscn); assert(scn); while ((data = elf_getdata(scn, data)) != 0) { uint32_t note_offset = 0; while (note_offset < data->d_size) { char* notec = (char *) data->d_buf + note_offset; Elf64_Nhdr* note = (Elf64_Nhdr*) notec; if (type == note->n_type) { std::string note_name = GetNoteString(note->n_namesz, notec + sizeof(Elf64_Nhdr)); if (name == note_name) { *desc = notec + sizeof(Elf64_Nhdr) + alignUp(note->n_namesz, 4); *desc_size = note->n_descsz; return true; } } note_offset += sizeof(Elf64_Nhdr) + alignUp(note->n_namesz, 4) + alignUp(note->n_descsz, 4); } } return false; } bool GElfRelocation::push(uint32_t type, Symbol* symbol, uint64_t offset, int64_t addend) { Rela()->r_info = GELF_R_INFO((uint64_t) symbol->index(), type); Rela()->r_offset = offset; Rela()->r_addend = addend; return true; } RelocationSection* GElfRelocation::section() { return rsection; } Symbol* GElfRelocation::symbol() { return rsection->symtab->symbol(symbolIndex()); } GElfRelocationSection::GElfRelocationSection(GElfImage* elf, Section* section_, GElfSymbolTable* symtab_) : GElfSection(elf), section(section_), symtab(symtab_) { } bool GElfRelocationSection::push(const std::string& name) { return GElfSection::push(name.c_str(), SHT_RELA, 0, symtab->getSectionIndex(), section->getSectionIndex(), 0, sizeof(Elf64_Rela)); } Relocation* GElfRelocationSection::addRelocation(uint32_t type, Symbol* symbol, uint64_t offset, int64_t addend) { GElfRelocation *rela = new (std::nothrow) GElfRelocation(this, data, data.reserve()); if (!rela || !rela->push(type, symbol, offset, addend)) { delete rela; return nullptr; } relocations.push_back(std::unique_ptr(rela)); return rela; } bool GElfRelocationSection::pullData() { section = elf->section(hdr.sh_info); symtab = elf->getReferencedSymbolTable(hdr.sh_link); Elf_Scn *lScn = elf_getscn(elf->e, ndxscn); assert(lScn); Elf_Data *lData = elf_getdata(lScn, nullptr); assert(lData); data0 = Buffer((const Buffer::byte_type*)lData->d_buf, lData->d_size, lData->d_align); for (size_t i = 0; i < data0.size() / sizeof(GElf_Rela); ++i) { relocations.push_back(std::unique_ptr(new GElfRelocation(this, data0, i * sizeof(GElf_Rela)))); } return true; } GElfImage::GElfImage(int elfclass_) : frozen(true), elfclass(elfclass_), buffer(0), bufferSize(0), e(0), shstrtabSection(0), strtabSection(0), symtabSection(0), dynsymSection(0), noteSection(0) { if (EV_NONE == elf_version(EV_CURRENT)) { assert(false); } } GElfImage::~GElfImage() { elf_end(e); } bool GElfImage::imgError() { out << img.output(); return false; } const char *GElfImage::elfError() { return elf_errmsg(-1); } bool GElfImage::elfBegin(Elf_Cmd cmd) { if ((e = elf_begin(img.fd(), cmd, NULL #ifdef AMD_LIBELF , NULL #endif )) == NULL) { out << "elf_begin failed: " << elfError() << std::endl; return false; } return true; } bool GElfImage::initNew(uint16_t machine, uint16_t type, uint8_t os_abi, uint8_t abi_version, uint32_t e_flags) { if (!img.create()) { return imgError(); } if (!elfBegin(ELF_C_WRITE)) { return false; } if (!gelf_newehdr(e, elfclass)) { return elfError("gelf_newehdr failed"); } if (!gelf_getehdr(e, &ehdr)) { return elfError("gelf_getehdr failed"); } ehdr.e_ident[EI_DATA] = ELFDATA2LSB; ehdr.e_ident[EI_VERSION] = EV_CURRENT; ehdr.e_ident[EI_OSABI] = os_abi; ehdr.e_ident[EI_ABIVERSION] = abi_version; ehdr.e_machine = machine; ehdr.e_type = type; ehdr.e_version = EV_CURRENT; ehdr.e_flags = e_flags; if (!gelf_update_ehdr(e, &ehdr)) { return elfError("gelf_updateehdr failed"); } sections.push_back(std::unique_ptr()); if (!shstrtab()->push(".shstrtab", SHT_STRTAB, SHF_STRINGS)) { return elfError("Failed to create shstrtab"); } ehdr.e_shstrndx = shstrtab()->getSectionIndex(); if (!gelf_update_ehdr(e, &ehdr)) { return elfError("gelf_updateehdr failed"); } if (!strtab()->push(".strtab", SHT_STRTAB, SHF_STRINGS)) { return elfError("Failed to create strtab"); } frozen = false; return true; } bool GElfImage::loadFromFile(const std::string& filename) { if (!img.create()) { return imgError(); } if (!img.readFrom(filename)) { return imgError(); } if (!elfBegin(ELF_C_RDWR)) { return false; } return pullElf(); } bool GElfImage::saveToFile(const std::string& filename) { if (buffer) { std::ofstream out(filename.c_str(), std::ios::binary); if (out.fail()) { return false; } out.write(buffer, bufferSize); return !out.fail(); } else { if (!push()) { return false; } return img.writeTo(filename); } } bool GElfImage::initFromBuffer(const void* buffer, size_t size) { if (size == 0) { size = ElfSize(buffer); } if (!img.create()) { return imgError(); } if (!img.copyFrom(buffer, size)) { return imgError(); } if (!elfBegin(ELF_C_RDWR)) { return false; } return pullElf(); } bool GElfImage::initAsBuffer(const void* buffer, size_t size) { if (size == 0) { size = ElfSize(buffer); } if ((e = elf_memory(reinterpret_cast(const_cast(buffer)), size #ifdef AMD_LIBELF , NULL #endif )) == NULL) { out << "elf_begin(buffer) failed: " << elfError() << std::endl; return false; } this->buffer = reinterpret_cast(buffer); this->bufferSize = size; return pullElf(); } bool GElfImage::pullElf() { if (!gelf_getehdr(e, &ehdr)) { return elfError("gelf_getehdr failed"); } segments.reserve(ehdr.e_phnum); for (size_t i = 0; i < ehdr.e_phnum; ++i) { GElfSegment* segment = new GElfSegment(this, i); segment->pull(); segments.push_back(std::unique_ptr(segment)); } shstrtabSection = new GElfStringTable(this); if (!shstrtabSection->pull(ehdr.e_shstrndx)) { return false; } Elf_Scn* scn = 0; for (unsigned n = 0; n < ehdr.e_shnum; ++n) { scn = elf_getscn(e, n); if (n == ehdr.e_shstrndx) { sections.push_back(std::unique_ptr(shstrtabSection)); continue; } GElf_Shdr shdr; if (!gelf_getshdr(scn, &shdr)) { return elfError("Failed to get shdr"); } GElfSection* section = 0; if (shdr.sh_type == SHT_NOTE) { section = new GElfNoteSection(this); } else if (shdr.sh_type == SHT_RELA) { section = new GElfRelocationSection(this); } else if (shdr.sh_type == SHT_STRTAB) { section = new GElfStringTable(this); } else if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) { section = new GElfSymbolTable(this); } else if (shdr.sh_type == SHT_NULL) { section = 0; sections.push_back(std::unique_ptr()); } else { section = new GElfSection(this); } if (section) { sections.push_back(std::unique_ptr(section)); if (!section->pull(n)) { return false; } } } for (size_t n = 1; n < sections.size(); ++n) { GElfSection* section = sections[n].get(); if (section->type() == SHT_STRTAB) { if (!section->pullData()) { return false; } } } for (size_t n = 1; n < sections.size(); ++n) { GElfSection* section = sections[n].get(); if (section->type() == SHT_SYMTAB || section->type() == SHT_DYNSYM) { if (!section->pullData()) { return false; } } } for (size_t n = 1; n < sections.size(); ++n) { GElfSection* section = sections[n].get(); if (section->type() != SHT_STRTAB && section->type() != SHT_SYMTAB && section->type() != SHT_DYNSYM) { if (!section->pullData()) { return false; } } } for (size_t i = 1; i < sections.size(); ++i) { if (i == ehdr.e_shstrndx) { continue; } std::unique_ptr& section = sections[i]; if (section->type() == SHT_STRTAB) { strtabSection = static_cast(section.get()); } if (section->type() == SHT_SYMTAB) { symtabSection = static_cast(section.get()); } if (section->type() == SHT_NOTE) { noteSection = static_cast(section.get()); } if (section->type() == SHT_DYNSYM) { dynsymSection = static_cast(section.get()); } } size_t phnum; if (elf_getphdrnum(e, &phnum) < 0) { return elfError("elf_getphdrnum failed"); } for (size_t i = 0; i < phnum; ++i) { segments.push_back(std::unique_ptr(new GElfSegment(this, i))); if (!segments[i]->pull()) { return false; } } return true; } bool GElfImage::elfError(const char* msg) { out << "Error: " << msg << ": " << elfError() << std::endl; return false; } uint64_t GElfImage::size() { if (buffer) { return ElfSize(buffer); } else { return img.getSize(); } } bool GElfImage::push0() { assert(e); for (std::unique_ptr& section : sections) { if (section && !section->push()) { return false; } } for (std::unique_ptr& section : sections) { if (section && !section->pull0()) { return false; } } if (!segments.empty()) { if (!gelf_newphdr(e, segments.size())) { return elfError("gelf_newphdr failed"); } } if (elf_update(e, ELF_C_NULL) < 0) { return elfError("elf_update (1.1) failed"); } if (!segments.empty()) { for (std::unique_ptr& section : sections) { // Update section offsets. if (section && !section->pull0()) { return false; } } uint64_t vaddr = 0; for (std::unique_ptr& segment : segments) { if (!segment->push(vaddr)) { return false; } vaddr = segment->vaddr() + segment->memSize(); } } return true; } bool GElfImage::push() { if (!push0()) { return false; } if (elf_update(e, ELF_C_WRITE) < 0) { return elfError("elf_update (2) failed"); } return true; } Segment* GElfImage::segmentByVAddr(uint64_t vaddr) { for (std::unique_ptr& seg : segments) { if (seg->vaddr() <= vaddr && vaddr < seg->vaddr() + seg->memSize()) { return seg.get(); } } return 0; } Section* GElfImage::sectionByVAddr(uint64_t vaddr) { for (size_t n = 1; n < sections.size(); ++n) { if (sections[n]->addr() <= vaddr && vaddr < sections[n]->addr() + sections[n]->size()) { return sections[n].get(); } } return nullptr; } bool GElfImage::elfEnd() { return false; } bool GElfImage::writeTo(const std::string& filename) { if (!img.writeTo(filename)) { return imgError(); } return true; } bool GElfImage::copyToBuffer(void** buf, size_t* size) { if (buffer) { *buf = malloc(bufferSize); memcpy(*buf, buffer, bufferSize); if (size) { *size = bufferSize; } return true; } else { return img.copyTo(buf, size); } } bool GElfImage::copyToBuffer(void* buf, size_t size) { if (buffer) { if (size < bufferSize) { return false; } memcpy(buf, buffer, bufferSize); return true; } else { return img.copyTo(buf, size); } } GElfStringTable* GElfImage::addStringTable(const std::string& name) { GElfStringTable* stab = new GElfStringTable(this); sections.push_back(std::unique_ptr(stab)); return stab; } GElfStringTable* GElfImage::getStringTable(uint16_t index) { return static_cast(sections[index].get()); } GElfSymbolTable* GElfImage::addSymbolTable(const std::string& name, StringTable* stab) { if (!stab) { stab = strtab(); } const char* name0 = shstrtab()->addString(name); GElfSymbolTable* symtab = new GElfSymbolTable(this); symtab->push(name0, static_cast(stab)); sections.push_back(std::unique_ptr(symtab)); return symtab; } GElfStringTable* GElfImage::shstrtab() { if (!shstrtabSection) { shstrtabSection = addStringTable(".shstrtab"); } return shstrtabSection; } GElfStringTable* GElfImage::strtab() { if (!strtabSection) { strtabSection = addStringTable(".shstrtab"); } return strtabSection; } GElfSymbolTable* GElfImage::symtab() { if (!symtabSection) { symtabSection = addSymbolTable(".symtab", strtab()); } return symtabSection; } GElfSymbolTable* GElfImage::dynsym() { if (!dynsymSection) { dynsymSection = addSymbolTable(".dynsym", strtab()); } return dynsymSection; } GElfSymbolTable* GElfImage::getSymbolTable() { const char *UseDynsym = getenv("LOADER_USE_DYNSYM"); if (UseDynsym && std::strncmp(UseDynsym, "0", 1) != 0) return dynsym(); return symtab(); } GElfNoteSection* GElfImage::note() { if (!noteSection) { noteSection = addNoteSection(".note"); } return noteSection; } GElfNoteSection* GElfImage::addNoteSection(const std::string& name) { GElfNoteSection* note = new GElfNoteSection(this); note->push(name); sections.push_back(std::unique_ptr(note)); return note; } Segment* GElfImage::initSegment(uint32_t type, uint32_t flags, uint64_t paddr) { GElfSegment *seg = new (std::nothrow) GElfSegment(this, segments.size(), type, flags, paddr); segments.push_back(std::unique_ptr(seg)); return seg; } bool GElfImage::addSegments() { return true; } Section* GElfImage::addSection(const std::string &name, uint32_t type, uint64_t flags, uint64_t entsize, Segment* segment) { GElfSection *section = new (std::nothrow) GElfSection(this); if (!section || !section->push(name.c_str(), type, flags, 0, 0, 0, entsize)) { delete section; return nullptr; } if (segment) { if (!segment->updateAddSection(section)) { delete section; return nullptr; } } sections.push_back(std::unique_ptr(section)); return section; } RelocationSection* GElfImage::addRelocationSection(Section* sec, SymbolTable* symtab) { std::string section_name = ".rela" + sec->Name(); if (!symtab) { symtab = this->symtab(); } GElfRelocationSection *rsec = new GElfRelocationSection(this, sec, (GElfSymbolTable*) symtab); if (!rsec || !rsec->push(section_name)) { delete rsec; return nullptr; } sections.push_back(std::unique_ptr(rsec)); return rsec; } RelocationSection* GElfImage::relocationSection(Section* sec, SymbolTable* symtab) { return sec->relocationSection(symtab); } uint16_t GElfImage::machine() const { return ehdr.e_machine; } uint16_t GElfImage::etype() const { return ehdr.e_type; } Image* NewElf32Image() { return new GElfImage(ELFCLASS32); } Image* NewElf64Image() { return new GElfImage(ELFCLASS64); } uint64_t ElfSize(const void* emi) { const Elf64_Ehdr *ehdr = (const Elf64_Ehdr*) emi; if (NULL == ehdr || EV_CURRENT != ehdr->e_version) { return false; } const Elf64_Shdr *shdr = (const Elf64_Shdr*)((char*)emi + ehdr->e_shoff); if (NULL == shdr) { return false; } uint64_t max_offset = ehdr->e_shoff; uint64_t total_size = max_offset + static_cast(ehdr->e_shentsize) * static_cast(ehdr->e_shnum); for (uint16_t i = 0; i < ehdr->e_shnum; ++i) { uint64_t cur_offset = static_cast(shdr[i].sh_offset); if (max_offset < cur_offset) { max_offset = cur_offset; total_size = max_offset; if (SHT_NOBITS != shdr[i].sh_type) { total_size += static_cast(shdr[i].sh_size); } } } return total_size; } std::string GetNoteString(uint32_t s_size, const char* s) { if (!s_size) { return ""; } if (s[s_size-1] == '\0') { return std::string(s, s_size-1); } else { return std::string(s, s_size); } } } // namespace elf } // namespace amd } // namespace rocr