aboutsummaryrefslogtreecommitdiff
path: root/core/elffile.cc
diff options
context:
space:
mode:
Diffstat (limited to 'core/elffile.cc')
-rw-r--r--core/elffile.cc5514
1 files changed, 5514 insertions, 0 deletions
diff --git a/core/elffile.cc b/core/elffile.cc
new file mode 100644
index 0000000..f4493a3
--- /dev/null
+++ b/core/elffile.cc
@@ -0,0 +1,5514 @@
+/**
+ * Support of ELF executable files.
+ */
+
+#include "../runtime/common.h"
+#include "../runtime/crypto.h"
+#include "objects.h"
+#include "osutils.h"
+#include "streams.h"
+#include "files.h"
+#include "dwarf.h"
+#include "elffile.h"
+#include "processors.h"
+#include "intel.h"
+#include "core.h"
+#include "lang.h"
+#include "script.h"
+
+#include "lin_runtime32.so.inc"
+#include "lin_runtime64.so.inc"
+
+/**
+ * ELFDirectory
+ */
+
+ELFDirectory::ELFDirectory(ELFDirectoryList *owner)
+ : BaseLoadCommand(owner), type_(0), value_(0)
+{
+
+}
+
+ELFDirectory::ELFDirectory(ELFDirectoryList *owner, size_t type)
+ : BaseLoadCommand(owner), type_(type), value_(0)
+{
+
+}
+
+ELFDirectory::ELFDirectory(ELFDirectoryList *owner, const ELFDirectory &src)
+ : BaseLoadCommand(owner)
+{
+ type_ = src.type_;
+ value_ = src.value_;
+ str_value_ = src.str_value_;
+}
+
+ELFDirectory *ELFDirectory::Clone(ILoadCommandList *owner) const
+{
+ ELFDirectory *dir = new ELFDirectory(reinterpret_cast<ELFDirectoryList *>(owner), *this);
+ return dir;
+}
+
+void ELFDirectory::ReadFromFile(ELFArchitecture &file)
+{
+ if (file.cpu_address_size() == osDWord) {
+ Elf32_Dyn dyn;
+ file.Read(&dyn, sizeof(dyn));
+ type_ = dyn.d_tag;
+ value_ = dyn.d_un.d_val;
+ } else {
+ Elf64_Dyn dyn;
+ file.Read(&dyn, sizeof(dyn));
+ type_ = dyn.d_tag;
+ value_ = dyn.d_un.d_val;
+ }
+}
+
+void ELFDirectory::ReadStrings(ELFStringTable &string_table)
+{
+ if (type_ == DT_NEEDED || type_ == DT_RPATH || type_ == DT_RUNPATH || type_ == DT_SONAME) {
+ if (value_ >> 32)
+ throw std::runtime_error("Invalid format");
+ str_value_ = string_table.GetString(static_cast<uint32_t>(value_));
+ }
+}
+
+void ELFDirectory::WriteStrings(ELFStringTable &string_table)
+{
+ if (type_ == DT_NEEDED || type_ == DT_RPATH || type_ == DT_RUNPATH || type_ == DT_SONAME)
+ value_ = string_table.AddString(str_value_);
+}
+
+size_t ELFDirectory::WriteToFile(ELFArchitecture &file)
+{
+ size_t res = 0;
+ if (file.cpu_address_size() == osDWord) {
+ Elf32_Dyn dyn;
+ dyn.d_tag = static_cast<uint32_t>(type_);
+ dyn.d_un.d_val = static_cast<uint32_t>(value_);
+ res += file.Write(&dyn, sizeof(dyn));
+ } else {
+ Elf64_Dyn dyn;
+ dyn.d_tag = type_;
+ dyn.d_un.d_val = value_;
+ res += file.Write(&dyn, sizeof(dyn));
+ }
+ return res;
+}
+
+std::string ELFDirectory::name() const
+{
+ switch (type_) {
+ case DT_NULL:
+ return std::string("DT_NULL");
+ case DT_NEEDED:
+ return std::string("DT_NEEDED");
+ case DT_PLTRELSZ:
+ return std::string("DT_PLTRELSZ");
+ case DT_PLTGOT:
+ return std::string("DT_PLTGOT");
+ case DT_HASH:
+ return std::string("DT_HASH");
+ case DT_STRTAB:
+ return std::string("DT_STRTAB");
+ case DT_SYMTAB:
+ return std::string("DT_SYMTAB");
+ case DT_RELA:
+ return std::string("DT_RELA");
+ case DT_RELASZ:
+ return std::string("DT_RELASZ");
+ case DT_RELAENT:
+ return std::string("DT_RELAENT");
+ case DT_STRSZ:
+ return std::string("DT_STRSZ");
+ case DT_SYMENT:
+ return std::string("DT_SYMENT");
+ case DT_INIT:
+ return std::string("DT_INIT");
+ case DT_FINI:
+ return std::string("DT_FINI");
+ case DT_SONAME:
+ return std::string("DT_SONAME");
+ case DT_RPATH:
+ return std::string("DT_RPATH");
+ case DT_SYMBOLIC:
+ return std::string("DT_SYMBOLIC");
+ case DT_REL:
+ return std::string("DT_REL");
+ case DT_RELSZ:
+ return std::string("DT_RELSZ");
+ case DT_RELENT:
+ return std::string("DT_RELENT");
+ case DT_PLTREL:
+ return std::string("DT_PLTREL");
+ case DT_DEBUG:
+ return std::string("DT_DEBUG");
+ case DT_TEXTREL:
+ return std::string("DT_TEXTREL");
+ case DT_JMPREL:
+ return std::string("DT_JMPREL");
+ case DT_BIND_NOW:
+ return std::string("DT_BIND_NOW");
+ case DT_INIT_ARRAY:
+ return std::string("DT_INIT_ARRAY");
+ case DT_FINI_ARRAY:
+ return std::string("DT_FINI_ARRAY");
+ case DT_INIT_ARRAYSZ:
+ return std::string("DT_INIT_ARRAYSZ");
+ case DT_FINI_ARRAYSZ:
+ return std::string("DT_FINI_ARRAYSZ");
+ case DT_RUNPATH:
+ return std::string("DT_RUNPATH");
+ case DT_FLAGS:
+ return std::string("DT_FLAGS");
+ case DT_PREINIT_ARRAY:
+ return std::string("DT_PREINIT_ARRAY");
+ case DT_PREINIT_ARRAYSZ:
+ return std::string("DT_PREINIT_ARRAYSZ");
+ case DT_GNU_HASH:
+ return std::string("DT_GNU_HASH");
+ case DT_RELACOUNT:
+ return std::string("DT_RELACOUNT");
+ case DT_RELCOUNT:
+ return std::string("DT_RELCOUNT");
+ case DT_FLAGS_1:
+ return std::string("DT_FLAGS_1");
+ case DT_VERSYM:
+ return std::string("DT_VERSYM");
+ case DT_VERDEF:
+ return std::string("DT_VERDEF");
+ case DT_VERDEFNUM:
+ return std::string("DT_VERDEFNUM");
+ case DT_VERNEED:
+ return std::string("DT_VERNEED");
+ case DT_VERNEEDNUM:
+ return std::string("DT_VERNEEDNUM");
+ }
+ return BaseLoadCommand::name();
+}
+
+void ELFDirectory::Rebase(uint64_t delta_base)
+{
+ switch (type_) {
+ case DT_PLTGOT:
+ value_ += delta_base;
+ break;
+ }
+}
+
+/**
+ * ELFDirectoryList
+ */
+
+ELFDirectoryList::ELFDirectoryList(ELFArchitecture *owner)
+ : BaseCommandList(owner)
+{
+
+}
+
+ELFDirectoryList::ELFDirectoryList(ELFArchitecture *owner, const ELFDirectoryList &src)
+ : BaseCommandList(owner, src)
+{
+
+}
+
+ELFDirectory *ELFDirectoryList::item(size_t index) const
+{
+ return reinterpret_cast<ELFDirectory *>(BaseCommandList::item(index));
+}
+
+ELFDirectory *ELFDirectoryList::GetCommandByType(uint32_t type) const
+{
+ return reinterpret_cast<ELFDirectory *>(BaseCommandList::GetCommandByType(type));
+}
+
+ELFDirectoryList *ELFDirectoryList::Clone(ELFArchitecture *owner) const
+{
+ ELFDirectoryList *list = new ELFDirectoryList(owner, *this);
+ return list;
+}
+
+ELFDirectory *ELFDirectoryList::Add()
+{
+ ELFDirectory *dir = new ELFDirectory(this);
+ AddObject(dir);
+ return dir;
+}
+
+ELFDirectory *ELFDirectoryList::Add(size_t type)
+{
+ ELFDirectory *dir = new ELFDirectory(this, type);
+ AddObject(dir);
+ return dir;
+}
+
+void ELFDirectoryList::ReadFromFile(ELFArchitecture &file)
+{
+ ELFSegment *segment = file.segment_list()->GetSectionByType(PT_DYNAMIC);
+ if (!segment)
+ return;
+
+ file.Seek(segment->physical_offset());
+ size_t entry_size = file.cpu_address_size() == osDWord ? sizeof(Elf32_Dyn) : sizeof(Elf64_Dyn);
+ for (uint64_t i = 0; i < segment->size(); i += entry_size) {
+ ELFDirectory *dir = Add();
+ dir->ReadFromFile(file);
+ if (dir->type() == DT_NULL) {
+ delete dir;
+ break;
+ }
+ }
+}
+
+void ELFDirectoryList::WriteToFile(ELFArchitecture &file)
+{
+ ELFSegment *segment = file.segment_list()->GetSectionByType(PT_DYNAMIC);
+ if (!segment)
+ return;
+
+ uint64_t address = file.AddressTell();
+ uint64_t pos = file.Tell();
+ size_t size = 0;
+ for (size_t i = 0; i < count(); i++) {
+ size += item(i)->WriteToFile(file);
+ }
+ ELFDirectory dt_null(NULL, DT_NULL);
+ size += dt_null.WriteToFile(file);
+
+ segment->Rebase(address - segment->address());
+ segment->set_physical_offset(static_cast<uint32_t>(pos));
+ segment->set_size(static_cast<uint32_t>(size));
+
+ ELFSection *section = file.section_list()->GetSectionByType(SHT_DYNAMIC);
+ if (section) {
+ section->Rebase(address - section->address());
+ section->set_physical_offset(static_cast<uint32_t>(pos));
+ section->set_size(static_cast<uint32_t>(size));
+ }
+}
+
+void ELFDirectoryList::ReadStrings(ELFStringTable &string_table)
+{
+ for (size_t i = 0; i < count(); i++) {
+ item(i)->ReadStrings(string_table);
+ }
+}
+
+void ELFDirectoryList::WriteStrings(ELFStringTable &string_table)
+{
+ for (size_t i = 0; i < count(); i++) {
+ item(i)->WriteStrings(string_table);
+ }
+}
+
+/**
+ * ELFSegment
+ */
+
+ELFSegment::ELFSegment(ELFSegmentList *owner)
+ : BaseSection(owner), type_(PT_NULL), address_(0), size_(0),
+ physical_offset_(0), physical_size_(0), flags_(0), alignment_(0)
+{
+
+}
+
+ELFSegment::ELFSegment(ELFSegmentList *owner, uint64_t address, uint64_t size, uint32_t physical_offset,
+ uint32_t physical_size, uint32_t flags, uint32_t type, uint64_t alignment)
+ : BaseSection(owner), address_(address), size_(size), physical_offset_(physical_offset), physical_size_(physical_size),
+ flags_(flags), type_(type), alignment_(alignment)
+{
+
+}
+
+ELFSegment::ELFSegment(ELFSegmentList *owner, const ELFSegment &src)
+ : BaseSection(owner, src)
+{
+ type_ = src.type_;
+ address_ = src.address_;
+ size_ = src.size_;
+ physical_offset_ = src.physical_offset_;
+ physical_size_ = src.physical_size_;
+ flags_ = src.flags_;
+ alignment_ = src.alignment_;
+}
+
+ELFSegment *ELFSegment::Clone(ISectionList *owner) const
+{
+ ELFSegment *segment = new ELFSegment(reinterpret_cast<ELFSegmentList *>(owner), *this);
+ return segment;
+}
+
+std::string ELFSegment::name() const
+{
+ switch (type_) {
+ case PT_NULL:
+ return std::string("PT_NULL");
+ case PT_LOAD:
+ return std::string("PT_LOAD");
+ case PT_DYNAMIC:
+ return std::string("PT_DYNAMIC");
+ case PT_INTERP:
+ return std::string("PT_INTERP");
+ case PT_NOTE:
+ return std::string("PT_NOTE");
+ case PT_SHLIB:
+ return std::string("PT_SHLIB");
+ case PT_PHDR:
+ return std::string("PT_PHDR");
+ case PT_TLS:
+ return std::string("PT_TLS");
+ case PT_GNU_EH_FRAME:
+ return std::string("PT_GNU_EH_FRAME");
+ case PT_GNU_STACK:
+ return std::string("PT_GNU_STACK");
+ case PT_GNU_RELRO:
+ return std::string("PT_GNU_RELRO");
+ }
+ return string_format("%d", type_);
+}
+
+uint32_t ELFSegment::memory_type() const
+{
+ uint32_t res = mtNone;
+ if (flags_ & PF_R)
+ res |= mtReadable;
+ if (flags_ & PF_W)
+ res |= mtWritable;
+ if (flags_ & PF_X)
+ res |= mtExecutable;
+ return res;
+}
+
+uint32_t ELFSegment::prot() const
+{
+ uint32_t res = PROT_NONE;
+ if (flags_ & PF_R)
+ res |= PROT_READ;
+ if (flags_ & PF_W)
+ res |= PROT_WRITE;
+ if (flags_ & PF_X)
+ res |= PROT_EXEC;
+ return res;
+}
+
+void ELFSegment::ReadFromFile(ELFArchitecture &file)
+{
+ if (file.cpu_address_size() == osDWord) {
+ Elf32_Phdr hdr;
+ file.Read(&hdr, sizeof(hdr));
+ type_ = hdr.p_type;
+ address_ = hdr.p_paddr;
+ size_ = hdr.p_memsz;
+ physical_offset_ = hdr.p_offset;
+ physical_size_ = hdr.p_filesz;
+ flags_ = hdr.p_flags;
+ alignment_ = hdr.p_align;
+ } else {
+ Elf64_Phdr hdr;
+ file.Read(&hdr, sizeof(hdr));
+ type_ = hdr.p_type;
+ address_ = hdr.p_paddr;
+ size_ = hdr.p_memsz;
+ if (hdr.p_offset >> 32)
+ throw std::runtime_error("Section size is too large");
+ if (hdr.p_filesz >> 32)
+ throw std::runtime_error("Section offset is too large");
+ physical_offset_ = static_cast<uint32_t>(hdr.p_offset);
+ physical_size_ = static_cast<uint32_t>(hdr.p_filesz);
+ flags_ = hdr.p_flags;
+ alignment_ = hdr.p_align;
+ }
+}
+
+size_t ELFSegment::WriteToFile(ELFArchitecture &file)
+{
+ size_t res = 0;
+ if (file.cpu_address_size() == osDWord) {
+ Elf32_Phdr hdr;
+ hdr.p_type = type_;
+ hdr.p_paddr = static_cast<uint32_t>(address_);
+ hdr.p_memsz = static_cast<uint32_t>(size_);
+ hdr.p_offset = physical_offset_;
+ hdr.p_vaddr = static_cast<uint32_t>(address_);
+ hdr.p_filesz = physical_size_;
+ hdr.p_flags = flags_;
+ hdr.p_align = static_cast<uint32_t>(alignment_);
+ res = file.Write(&hdr, sizeof(hdr));
+ } else {
+ Elf64_Phdr hdr;
+ hdr.p_type = type_;
+ hdr.p_paddr = address_;
+ hdr.p_memsz = size_;
+ hdr.p_offset = physical_offset_;
+ hdr.p_vaddr = address_;
+ hdr.p_filesz = physical_size_;
+ hdr.p_flags = flags_;
+ hdr.p_align = alignment_;
+ res = file.Write(&hdr, sizeof(hdr));
+ }
+ return res;
+}
+
+void ELFSegment::update_type(uint32_t mt)
+{
+ if (mt & mtReadable)
+ flags_ |= PF_R;
+ if (mt & mtWritable)
+ flags_ |= PF_W;
+ if (mt & mtExecutable)
+ flags_ |= PF_X;
+}
+
+void ELFSegment::Rebase(uint64_t delta_base)
+{
+ address_ += delta_base;
+}
+
+/**
+ * ELFSegmentList
+ */
+
+ELFSegmentList::ELFSegmentList(ELFArchitecture *owner)
+ : BaseSectionList(owner)
+{
+
+}
+
+ELFSegmentList::ELFSegmentList(ELFArchitecture *owner, const ELFSegmentList &src)
+ : BaseSectionList(owner, src)
+{
+
+}
+
+ELFSegmentList *ELFSegmentList::Clone(ELFArchitecture *owner) const
+{
+ ELFSegmentList *list = new ELFSegmentList(owner, *this);
+ return list;
+}
+
+ELFSegment *ELFSegmentList::item(size_t index) const
+{
+ return reinterpret_cast<ELFSegment*>(BaseSectionList::item(index));
+}
+
+ELFSegment *ELFSegmentList::last() const
+{
+ for (size_t i = count(); i > 0 ; i--) {
+ ELFSegment *segment = item(i - 1);
+ if (segment->type() == PT_LOAD)
+ return segment;
+ }
+ return NULL;
+}
+
+ELFSegment *ELFSegmentList::Add()
+{
+ ELFSegment *segment = new ELFSegment(this);
+ AddObject(segment);
+ return segment;
+}
+
+void ELFSegmentList::ReadFromFile(ELFArchitecture &file, size_t count)
+{
+ for (size_t i = 0; i < count; i++) {
+ Add()->ReadFromFile(file);
+ }
+}
+
+size_t ELFSegmentList::WriteToFile(ELFArchitecture &file)
+{
+ size_t res = 0;
+ for (size_t i = 0; i < count(); i++) {
+ res += item(i)->WriteToFile(file);
+ }
+ return res;
+}
+
+ELFSegment *ELFSegmentList::Add(uint64_t address, uint64_t size, uint32_t physical_offset, uint32_t physical_size,
+ uint32_t initprot, uint32_t type, uint64_t alignment)
+{
+ ELFSegment *segment = new ELFSegment(this, address, size, physical_offset, physical_size, initprot, type, alignment);
+ AddObject(segment);
+ return segment;
+}
+
+ELFSegment *ELFSegmentList::GetSectionByAddress(uint64_t address) const
+{
+ for (size_t i = 0; i < count(); i++) {
+ ELFSegment *segment = item(i);
+ if (segment->type() != PT_LOAD)
+ continue;
+
+ if (address >= segment->address() && address < segment->address() + segment->size())
+ return segment;
+ }
+ return NULL;
+}
+
+ELFSegment *ELFSegmentList::GetSectionByOffset(uint64_t offset) const
+{
+ for (size_t i = 0; i < count(); i++) {
+ ELFSegment *segment = item(i);
+ if (segment->type() != PT_LOAD)
+ continue;
+
+ if (offset >= segment->physical_offset() && offset < static_cast<uint64_t>(segment->physical_offset()) + static_cast<uint64_t>(segment->physical_size()))
+ return segment;
+ }
+ return NULL;
+}
+
+ELFSegment *ELFSegmentList::GetSectionByType(uint32_t type) const
+{
+ for (size_t i = 0; i < count(); i++) {
+ ELFSegment *segment = item(i);
+ if (segment->type() == type)
+ return segment;
+ }
+ return NULL;
+}
+
+/**
+ * ELFStringTable
+ */
+
+ELFStringTable *ELFStringTable::Clone()
+{
+ ELFStringTable *table = new ELFStringTable(*this);
+ return table;
+}
+
+std::string ELFStringTable::GetString(uint32_t pos) const
+{
+ size_t i, len;
+
+ if (pos >= data_.size())
+ throw std::runtime_error("Invalid index for string table");
+
+ len = data_.size() - pos;
+ for (i = 0; i < len; i++) {
+ if (data_[pos + i] == 0) {
+ len = i;
+ break;
+ }
+ }
+ if (len == data_.size() - pos)
+ throw std::runtime_error("Invalid format");
+
+ return std::string(&data_[pos], len);
+}
+
+uint32_t ELFStringTable::AddString(const std::string &str)
+{
+ if (str.empty())
+ return 0;
+
+ std::map<std::string, uint32_t>::const_iterator it = map_.find(str);
+ if (it != map_.end())
+ return it->second;
+
+ uint32_t res = static_cast<uint32_t>(data_.size());
+ data_.insert(data_.end(), str.c_str(), str.c_str() + str.size() + 1);
+ map_[str] = res;
+ return res;
+};
+
+void ELFStringTable::clear()
+{
+ data_.clear();
+ data_.push_back(0);
+ map_.clear();
+}
+
+void ELFStringTable::ReadFromFile(ELFArchitecture &file)
+{
+ ELFDirectory *dir = file.command_list()->GetCommandByType(DT_STRTAB);
+ if (!dir)
+ return;
+
+ ELFDirectory *size = file.command_list()->GetCommandByType(DT_STRSZ);
+ if (!size || !file.AddressSeek(dir->value()))
+ throw std::runtime_error("Invalid format");
+
+ data_.resize(static_cast<size_t>(size->value()));
+ file.Read(data_.data(), data_.size());
+}
+
+void ELFStringTable::ReadFromFile(ELFArchitecture &file, const ELFSection &section)
+{
+ if (section.type() != SHT_STRTAB)
+ throw std::runtime_error("Invalid format");
+
+ file.Seek(section.physical_offset());
+ data_.resize(static_cast<uint32_t>(section.size()));
+ file.Read(data_.data(), data_.size());
+}
+
+size_t ELFStringTable::WriteToFile(ELFArchitecture &file)
+{
+ size_t res = file.Write(data_.data(), data_.size());
+ return res;
+}
+
+/**
+ * ELFSection
+ */
+
+ELFSection::ELFSection(ELFSectionList *owner)
+ : BaseSection(owner), address_(0), size_(0), type_(0), physical_offset_(0), name_idx_(0),
+ link_(0), flags_(0), entry_size_(0), parent_(0), info_(0), addralign_(1)
+{
+
+}
+
+ELFSection::ELFSection(ELFSectionList *owner, uint64_t address, uint32_t size, uint32_t physical_offset, uint32_t flags, uint32_t type, const std::string &name)
+ : BaseSection(owner), address_(address), size_(size), type_(type), physical_offset_(physical_offset), name_idx_(0),
+ link_(0), flags_(flags), entry_size_(0), parent_(0), name_(name), info_(0), addralign_(1)
+{
+
+}
+
+ELFSection::ELFSection(ELFSectionList *owner, const ELFSection &src)
+ : BaseSection(owner, src), parent_(0)
+{
+ address_ = src.address_;
+ size_ = src.size_;
+ type_ = src.type_;
+ physical_offset_ = src.physical_offset_;
+ flags_ = src.flags_;
+ entry_size_ = src.entry_size_;
+ link_ = src.link_;
+ info_ = src.info_;
+ addralign_ = src.addralign_;
+ name_ = src.name_;
+ name_idx_ = src.name_idx_;
+ if (src.parent_)
+ {
+ ELFArchitecture *thisArc = dynamic_cast<ELFArchitecture *>(owner->owner());
+ assert(thisArc);
+ assert(thisArc->segment_list());
+ if (thisArc && thisArc->segment_list())
+ parent_ = thisArc->segment_list()->GetSectionByAddress(address_);
+ assert(parent_);
+ }
+}
+
+ELFSection *ELFSection::Clone(ISectionList *owner) const
+{
+ ELFSection *section = new ELFSection(reinterpret_cast<ELFSectionList *>(owner), *this);
+ return section;
+}
+
+void ELFSection::ReadFromFile(ELFArchitecture &file)
+{
+ if (file.cpu_address_size() == osDWord) {
+ Elf32_Shdr hdr;
+ file.Read(&hdr, sizeof(hdr));
+ name_idx_ = hdr.sh_name;
+ type_ = hdr.sh_type;
+ address_ = hdr.sh_addr;
+ size_ = hdr.sh_size;
+ physical_offset_ = hdr.sh_offset;
+ flags_ = hdr.sh_flags;
+ entry_size_ = hdr.sh_entsize;
+ link_ = hdr.sh_link;
+ info_ = hdr.sh_info;
+ addralign_ = hdr.sh_addralign;
+ } else {
+ Elf64_Shdr hdr;
+ file.Read(&hdr, sizeof(hdr));
+ if (hdr.sh_size >> 32)
+ throw std::runtime_error("Section size is too large");
+ if (hdr.sh_offset >> 32)
+ throw std::runtime_error("Section offset is too large");
+ name_idx_ = hdr.sh_name;
+ type_ = hdr.sh_type;
+ address_ = hdr.sh_addr;
+ size_ = static_cast<uint32_t>(hdr.sh_size);
+ physical_offset_ = static_cast<uint32_t>(hdr.sh_offset);
+ flags_ = hdr.sh_flags;
+ entry_size_ = hdr.sh_entsize;
+ link_ = hdr.sh_link;
+ info_ = hdr.sh_info;
+ addralign_ = static_cast<uint32_t>(hdr.sh_addralign);
+ }
+
+ if (address_)
+ parent_ = file.segment_list()->GetSectionByAddress(address_);
+}
+
+void ELFSection::ReadName(ELFStringTable &strtab)
+{
+ name_ = strtab.GetString(name_idx_);
+}
+
+void ELFSection::WriteName(ELFStringTable &strtab)
+{
+ name_idx_ = strtab.AddString(name_);
+}
+
+void ELFSection::WriteToFile(ELFArchitecture &file)
+{
+ if (file.cpu_address_size() == osDWord) {
+ Elf32_Shdr hdr;
+ hdr.sh_name = name_idx_;
+ hdr.sh_type = type_;
+ hdr.sh_addr = static_cast<uint32_t>(address_);
+ hdr.sh_size = size_;
+ hdr.sh_offset = physical_offset_;
+ hdr.sh_flags = static_cast<uint32_t>(flags_);
+ hdr.sh_entsize = static_cast<uint32_t>(entry_size_);
+ hdr.sh_link = link_;
+ hdr.sh_info = info_;
+ hdr.sh_addralign = static_cast<uint32_t>(addralign_);
+ file.Write(&hdr, sizeof(hdr));
+ } else {
+ Elf64_Shdr hdr;
+ hdr.sh_name = name_idx_;
+ hdr.sh_type = type_;
+ hdr.sh_addr = address_;
+ hdr.sh_size = size_;
+ hdr.sh_offset = physical_offset_;
+ hdr.sh_flags = flags_;
+ hdr.sh_entsize = entry_size_;
+ hdr.sh_link = link_;
+ hdr.sh_info = info_;
+ hdr.sh_addralign = addralign_;
+ file.Write(&hdr, sizeof(hdr));
+ }
+}
+
+void ELFSection::Rebase(uint64_t delta_base)
+{
+ address_ += delta_base;
+}
+
+void ELFSection::RemapLinks(const std::map<size_t, size_t> &index_map)
+{
+ std::map<size_t, size_t>::const_iterator it;
+
+ switch (type_) {
+ case SHT_DYNAMIC:
+ case SHT_HASH:
+ case SHT_REL:
+ case SHT_RELA:
+ case SHT_SYMTAB:
+ case SHT_DYNSYM:
+ case SHT_GNU_HASH:
+ case SHT_GNU_versym:
+ case SHT_GNU_verneed:
+ it = index_map.find(link_);
+ if (it == index_map.end() || it->second == NOT_ID)
+ throw std::runtime_error("Invalid section index");
+
+ link_ = static_cast<uint32_t>(it->second);
+ break;
+ }
+
+ switch (type_) {
+ case SHT_REL:
+ case SHT_RELA:
+ it = index_map.find(info_);
+ if (it == index_map.end() || it->second == NOT_ID)
+ throw std::runtime_error("Invalid section index");
+
+ info_ = static_cast<uint32_t>(it->second);
+ break;
+ }
+}
+
+/**
+ * ELFSectionList
+ */
+
+ELFSectionList::ELFSectionList(ELFArchitecture *owner)
+ : BaseSectionList(owner)
+{
+
+}
+
+ELFSectionList::ELFSectionList(ELFArchitecture *owner, const ELFSectionList &src)
+ : BaseSectionList(owner, src)
+{
+
+}
+
+ELFSection *ELFSectionList::item(size_t index) const
+{
+ return reinterpret_cast<ELFSection *>(BaseSectionList::item(index));
+}
+
+ELFSectionList *ELFSectionList::Clone(ELFArchitecture *owner) const
+{
+ ELFSectionList *section_list = new ELFSectionList(owner, *this);
+ return section_list;
+}
+
+ELFSection *ELFSectionList::Add()
+{
+ ELFSection *section = new ELFSection(this);
+ AddObject(section);
+ return section;
+}
+
+ELFSection *ELFSectionList::Add(uint64_t address, uint32_t size, uint32_t physical_offset, uint32_t flags, uint32_t type, const std::string &name)
+{
+ ELFSection *section = new ELFSection(this, address, size, physical_offset, flags, type, name);
+ AddObject(section);
+ return section;
+}
+
+void ELFSectionList::ReadFromFile(ELFArchitecture &file, size_t count)
+{
+ size_t i;
+ for (i = 0; i < count; i++) {
+ ELFSection *section = Add();
+ section->ReadFromFile(file);
+ }
+
+ if (file.shstrndx() != SHN_UNDEF) {
+ string_table_.ReadFromFile(file, *file.section_list()->item(file.shstrndx()));
+ for (i = 0; i < count; i++) {
+ item(i)->ReadName(string_table_);
+ }
+ }
+}
+
+uint64_t ELFSectionList::WriteToFile(ELFArchitecture &file)
+{
+ string_table_.clear();
+ for (size_t i = 0; i < count(); i++) {
+ item(i)->WriteName(string_table_);
+ }
+ uint64_t pos = file.Tell();
+ size_t size = string_table_.WriteToFile(file);
+ ELFSection *section = item(file.shstrndx());
+ section->set_physical_offset(static_cast<uint32_t>(pos));
+ section->set_size(static_cast<uint32_t>(size));
+
+ pos = file.Tell();
+ for (size_t i = 0; i < count(); i++) {
+ item(i)->WriteToFile(file);
+ }
+ return pos;
+}
+
+ELFSection *ELFSectionList::GetSectionByType(uint32_t type) const
+{
+ for (size_t i = 0; i < count(); i++) {
+ ELFSection *section = item(i);
+ if (section->type() == type)
+ return section;
+ }
+ return NULL;
+}
+
+ELFSection *ELFSectionList::GetSectionByAddress(uint64_t address) const
+{
+ return reinterpret_cast<ELFSection *>(BaseSectionList::GetSectionByAddress(address));
+}
+
+ELFSection *ELFSectionList::GetSectionByName(const std::string &name) const
+{
+ return reinterpret_cast<ELFSection *>(BaseSectionList::GetSectionByName(name));
+}
+
+void ELFSectionList::RemapLinks(const std::map<size_t, size_t> &index_map)
+{
+ for (size_t i = 0; i < count(); i++) {
+ item(i)->RemapLinks(index_map);
+ }
+}
+
+/**
+ * ELFImportFunction
+ */
+
+ELFImportFunction::ELFImportFunction(ELFImport *owner, uint64_t address, const std::string &name, ELFSymbol *symbol)
+ : BaseImportFunction(owner), address_(address), name_(name), symbol_(symbol)
+{
+
+}
+
+ELFImportFunction::ELFImportFunction(ELFImport *owner, uint64_t address, APIType type, MapFunction *map_function)
+ : BaseImportFunction(owner), address_(address), symbol_(NULL)
+{
+ set_type(type);
+ set_map_function(map_function);
+}
+
+ELFImportFunction::ELFImportFunction(ELFImport *owner, const ELFImportFunction &src)
+ : BaseImportFunction(owner, src)
+{
+ address_ = src.address_;
+ name_ = src.name_;
+ symbol_ = src.symbol_;
+}
+
+ELFImportFunction *ELFImportFunction::Clone(IImport *owner) const
+{
+ ELFImportFunction *func = new ELFImportFunction(reinterpret_cast<ELFImport*>(owner), *this);
+ return func;
+}
+
+/**
+ * ELFImport
+ */
+
+ELFImport::ELFImport(ELFImportList *owner, bool is_sdk)
+ : BaseImport(owner), is_sdk_(is_sdk)
+{
+
+}
+
+ELFImport::ELFImport(ELFImportList *owner, const std::string &name)
+ : BaseImport(owner), name_(name), is_sdk_(false)
+{
+
+}
+
+ELFImport::ELFImport(ELFImportList *owner, const ELFImport &src)
+ : BaseImport(owner, src)
+{
+ name_ = src.name_;
+ is_sdk_ = src.is_sdk_;
+}
+
+ELFImportFunction *ELFImport::item(size_t index) const
+{
+ return reinterpret_cast<ELFImportFunction*>(BaseImport::item(index));
+}
+
+ELFImportFunction *ELFImport::GetFunctionBySymbol(ELFSymbol *symbol) const
+{
+ for (size_t i = 0; i < count(); i++) {
+ ELFImportFunction *func = item(i);
+ if (func->symbol() == symbol)
+ return func;
+ }
+ return NULL;
+}
+
+ELFImport *ELFImport::Clone(IImportList *owner) const
+{
+ ELFImport *list = new ELFImport(reinterpret_cast<ELFImportList *>(owner), *this);
+ return list;
+}
+
+IImportFunction *ELFImport::Add(uint64_t address, APIType type, MapFunction *map_function)
+{
+ ELFImportFunction *import_function = new ELFImportFunction(this, address, type, map_function);
+ AddObject(import_function);
+ return import_function;
+}
+
+ELFImportFunction *ELFImport::Add(uint64_t address, const std::string &name, ELFSymbol *symbol)
+{
+ ELFImportFunction *import_function = new ELFImportFunction(this, address, name, symbol);
+ AddObject(import_function);
+ return import_function;
+}
+
+void ELFImportFunction::Rebase(uint64_t delta_base)
+{
+ if (address_)
+ address_ += delta_base;
+}
+
+std::string ELFImportFunction::display_name(bool show_ret) const
+{
+ return DemangleName(name_).display_name(show_ret);
+}
+
+/**
+ * ELFImportList
+ */
+
+ELFImportList::ELFImportList(ELFArchitecture *owner)
+ : BaseImportList(owner)
+{
+
+}
+
+ELFImportList::ELFImportList(ELFArchitecture *owner, const ELFImportList &src)
+ : BaseImportList(owner, src)
+{
+
+}
+
+ELFImportList *ELFImportList::Clone(ELFArchitecture *owner) const
+{
+ ELFImportList *list = new ELFImportList(owner, *this);
+ return list;
+}
+
+ELFImport *ELFImportList::item(size_t index) const
+{
+ return reinterpret_cast<ELFImport*>(IImportList::item(index));
+}
+
+ELFImportFunction *ELFImportList::GetFunctionByAddress(uint64_t address) const
+{
+ return reinterpret_cast<ELFImportFunction*>(BaseImportList::GetFunctionByAddress(address));
+}
+
+ELFImport *ELFImportList::Add(const std::string &name)
+{
+ ELFImport *import = new ELFImport(this, name);
+ AddObject(import);
+ return import;
+}
+
+ELFImport *ELFImportList::AddSDK()
+{
+ ELFImport *sdk = new ELFImport(this, true);
+ AddObject(sdk);
+ return sdk;
+}
+
+void ELFImportList::ReadFromFile(ELFArchitecture &file)
+{
+ static const ImportInfo default_info[] = {
+ {atNone, "exit", ioNoReturn, ctNone},
+ {atNone, "abort", ioNoReturn, ctNone},
+ {atNone, "longjmp", ioNoReturn, ctNone},
+ {atNone, "longjmp_chk", ioNoReturn, ctNone},
+ {atNone, "_Unwind_Resume", ioNoReturn, ctNone},
+ {atNone, "__stack_chk_fail", ioNoReturn, ctNone},
+ {atNone, "__cxa_throw", ioNoReturn, ctNone},
+ {atNone, "__cxa_end_cleanup", ioNoReturn, ctNone},
+ {atNone, "__cxa_rethrow", ioNoReturn, ctNone},
+ {atNone, "__cxa_bad_cast", ioNoReturn, ctNone},
+ {atNone, "__cxa_bad_typeid", ioNoReturn, ctNone},
+ {atNone, "__cxa_call_terminate", ioNoReturn, ctNone},
+ {atNone, "__cxa_pure_virtual", ioNoReturn, ctNone},
+ {atNone, "__cxa_call_unexpected", ioNoReturn, ctNone},
+ {atNone, "_ZSt9terminatev", ioNoReturn, ctNone},
+ {atNone, "_ZSt16__throw_bad_castv", ioNoReturn, ctNone},
+ {atNone, "_ZSt17__throw_bad_allocv", ioNoReturn, ctNone},
+ {atNone, "_ZSt19__throw_logic_errorPKc", ioNoReturn, ctNone},
+ {atNone, "_ZSt20__throw_system_errori", ioNoReturn, ctNone},
+ {atNone, "_ZSt20__throw_length_errorPKc", ioNoReturn, ctNone},
+ {atNone, "_ZSt24__throw_invalid_argumentPKc", ioNoReturn, ctNone},
+ {atNone, "_ZSt20__throw_out_of_rangePKc", ioNoReturn, ctNone},
+ {atNone, "_ZSt24__throw_out_of_range_fmtPKcz", ioNoReturn, ctNone}
+ };
+
+ size_t i, j, k;
+
+ ELFImport *sdk_import = NULL;
+ std::string sdk_name = string_format("libvmprotectsdk%d.so", (file.cpu_address_size() == osDWord) ? 32 : 64);
+ ELFSymbolList *symbol_list = file.dynsymbol_list();
+ for (i = 0; i < file.command_list()->count(); i++) {
+ ELFDirectory *dir = file.command_list()->item(i);
+ switch (dir->type()) {
+ case DT_NEEDED:
+ {
+ ELFImport *import = Add(dir->str_value());
+ std::string dll_name = os::ExtractFileName(import->name().c_str());
+ std::transform(dll_name.begin(), dll_name.end(), dll_name.begin(), tolower);
+ if (dll_name.compare(sdk_name) == 0) {
+ import->set_is_sdk(true);
+ if (!sdk_import)
+ sdk_import = import;
+ }
+ }
+ break;
+ }
+ }
+
+ std::map<ELFSymbol *, std::vector<uint64_t> > symbol_map;
+ ELFRelocationList *relocation_list = file.relocation_list();
+ for (i = 0; i < relocation_list->count(); i++) {
+ ELFRelocation *reloc = relocation_list->item(i);
+ std::map<ELFSymbol *, std::vector<uint64_t> >::iterator it = symbol_map.find(reloc->symbol());
+ if (it != symbol_map.end())
+ it->second.push_back(reloc->address());
+ else
+ symbol_map[reloc->symbol()].push_back(reloc->address());
+ }
+
+ std::map<uint16_t, ELFImport *> version_map;
+ for (i = 0; i < file.verneed_list()->count(); i++) {
+ ELFVerneed *verneed = file.verneed_list()->item(i);
+ ELFImport *import = GetImportByName(verneed->file());
+ for (j = 0; j < verneed->count(); j++) {
+ ELFVernaux *vernaux = verneed->item(j);
+ version_map[vernaux->other()] = import;
+ }
+ }
+
+ ELFImport *empty_import = NULL;
+ for (i = 0; i < symbol_list->count(); i++) {
+ ELFSymbol *symbol = symbol_list->item(i);
+ if (symbol->section_idx() || symbol->name().empty())
+ continue;
+
+ ELFImport *import = (sdk_import && GetSDKInfo(symbol->name())) ? sdk_import : NULL;
+ if (!import && symbol->version() > 1) {
+ std::map<uint16_t, ELFImport *>::const_iterator it = version_map.find(symbol->version());
+ if (it != version_map.end())
+ import = it->second;
+ }
+ if (!import) {
+ if (!empty_import)
+ empty_import = Add("");
+ import = empty_import;
+ }
+
+ std::vector<uint64_t> address_list;
+ std::map<ELFSymbol *, std::vector<uint64_t> >::const_iterator it = symbol_map.find(symbol);
+ if (it != symbol_map.end())
+ address_list = it->second;
+ else
+ address_list.push_back(0);
+
+ for (j = 0; j < address_list.size(); j++) {
+ import->Add(address_list[j], symbol->name(), symbol);
+ }
+ }
+
+ ELFImportFunction *func;
+ for (k = 0; k < count(); k++) {
+ ELFImport *import = item(k);
+
+ if (import->is_sdk()) {
+ import->set_is_sdk(true);
+ for (i = 0; i < import->count(); i++) {
+ func = import->item(i);
+ const ImportInfo *import_info = GetSDKInfo(func->name());
+ if (import_info) {
+ func->set_type(import_info->type);
+ if (import_info->options & ioHasCompilationType) {
+ func->include_option(ioHasCompilationType);
+ func->set_compilation_type(import_info->compilation_type);
+ if (import_info->options & ioLockToKey)
+ func->include_option(ioLockToKey);
+ }
+ }
+ }
+ } else {
+ size_t c = _countof(default_info);
+ const ImportInfo *import_info = default_info;
+
+ if (import_info) {
+ for (i = 0; i < import->count(); i++) {
+ func = import->item(i);
+ for (j = 0; j < c; j++) {
+ if (func->name().compare(import_info[j].name) == 0) {
+ func->set_type(import_info[j].type);
+ if (import_info[j].options & ioNative)
+ func->include_option(ioNative);
+ if (import_info[j].options & ioNoReturn)
+ func->include_option(ioNoReturn);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void ELFImportList::Pack()
+{
+ for (size_t i = count(); i > 0; i--) {
+ ELFImport *import = item(i - 1);
+ if (!import->is_sdk())
+ continue;
+
+ for (size_t j = 0; j < import->count(); j++) {
+ import->item(j)->symbol()->set_deleted(true);
+ }
+ delete import;
+ }
+}
+
+void ELFImportList::WriteToFile(ELFArchitecture &file)
+{
+ size_t i;
+ ELFDirectory *dir;
+
+ ELFDirectoryList *directory_list = file.command_list();
+ for (i = directory_list->count(); i > 0; i--) {
+ dir = directory_list->item(i - 1);
+ if (dir->type() == DT_NEEDED)
+ delete dir;
+ }
+
+ size_t j = 0;
+ for (i = 0; i < count(); i++) {
+ ELFImport *import = item(i);
+ if (import->name().empty())
+ continue;
+
+ dir = new ELFDirectory(directory_list, DT_NEEDED);
+ directory_list->InsertObject(j++, dir);
+ dir->set_str_value(import->name());
+ }
+}
+
+ELFImport *ELFImportList::GetImportByName(const std::string &name) const
+{
+ return reinterpret_cast<ELFImport *>(BaseImportList::GetImportByName(name));
+}
+
+/**
+ * ELFFixup
+ */
+
+ELFFixup::ELFFixup(ELFFixupList *owner, uint64_t address, OperandSize size)
+ : BaseFixup(owner), address_(address), size_(size)
+{
+
+}
+
+ELFFixup::ELFFixup(ELFFixupList *owner, const ELFFixup &src)
+ : BaseFixup(owner, src)
+{
+ address_ = src.address_;
+ size_ = src.size_;
+}
+
+ELFFixup *ELFFixup::Clone(IFixupList *owner) const
+{
+ ELFFixup *fixup = new ELFFixup(reinterpret_cast<ELFFixupList *>(owner), *this);
+ return fixup;
+}
+
+void ELFFixup::Rebase(IArchitecture &file, uint64_t delta_base)
+{
+ if (!file.AddressSeek(address_))
+ return;
+
+ uint64_t value = 0;
+ uint64_t pos = file.Tell();
+ size_t value_size = OperandSizeToValue(size_);
+ value = 0;
+ file.Read(&value, value_size);
+ value += delta_base;
+ file.Seek(pos);
+ file.Write(&value, value_size);
+
+ address_ += delta_base;
+}
+
+/**
+ * ELFFixupList
+ */
+
+ELFFixupList::ELFFixupList()
+ : BaseFixupList()
+{
+
+}
+
+ELFFixupList::ELFFixupList(const ELFFixupList &src)
+ : BaseFixupList(src)
+{
+
+}
+
+ELFFixupList *ELFFixupList::Clone() const
+{
+ ELFFixupList *list = new ELFFixupList(*this);
+ return list;
+}
+
+ELFFixup *ELFFixupList::item(size_t index) const
+{
+ return reinterpret_cast<ELFFixup *>(BaseFixupList::item(index));
+}
+
+IFixup *ELFFixupList::AddDefault(OperandSize cpu_address_size, bool is_code)
+{
+ ELFFixup *fixup = new ELFFixup(this, 0, cpu_address_size);
+ AddObject(fixup);
+ return fixup;
+}
+
+ELFFixup *ELFFixupList::Add(uint64_t address, OperandSize size)
+{
+ ELFFixup *fixup = new ELFFixup(this, address, size);
+ AddObject(fixup);
+ return fixup;
+}
+
+void ELFFixupList::WriteToData(Data &data, uint64_t image_base)
+{
+ size_t i, size_pos;
+ ELFFixup *fixup;
+ IMAGE_BASE_RELOCATION reloc;
+ uint32_t rva, block_rva;
+ uint16_t type_offset, empty_offset;
+
+ Sort();
+
+ size_pos = 0;
+ reloc.VirtualAddress = 0;
+ reloc.SizeOfBlock = 0;
+
+ for (i = 0; i < count(); i++) {
+ fixup = item(i);
+
+ rva = static_cast<uint32_t>(fixup->address() - image_base);
+ block_rva = rva & 0xfffff000;
+ if (reloc.SizeOfBlock == 0 || block_rva != reloc.VirtualAddress) {
+ if (reloc.SizeOfBlock > 0) {
+ if ((reloc.SizeOfBlock & 3) != 0) {
+ data.PushWord(empty_offset);
+ reloc.SizeOfBlock += sizeof(empty_offset);
+ }
+ data.WriteDWord(size_pos, reloc.SizeOfBlock);
+ }
+ size_pos = data.size() + 4;
+ reloc.VirtualAddress = block_rva;
+ reloc.SizeOfBlock = sizeof(reloc);
+ data.PushBuff(&reloc, sizeof(reloc));
+ empty_offset = (static_cast<uint16_t>(rva - block_rva) & 0xf00) << 4 | R_386_NONE;
+ }
+ type_offset = (static_cast<uint16_t>(rva - block_rva) & 0xfff) << 4 | R_386_RELATIVE;
+ data.PushWord(type_offset);
+ reloc.SizeOfBlock += sizeof(type_offset);
+ }
+
+ if (reloc.SizeOfBlock > 0) {
+ if ((reloc.SizeOfBlock & 3) != 0) {
+ data.PushWord(empty_offset);
+ reloc.SizeOfBlock += sizeof(empty_offset);
+ }
+ data.WriteDWord(size_pos, reloc.SizeOfBlock);
+ }
+}
+
+/**
+ * ELFExport
+ */
+
+ELFExport::ELFExport(IExportList *parent, uint64_t address)
+ : BaseExport(parent), symbol_(NULL), address_(address), type_(atNone)
+{
+
+}
+
+ELFExport::ELFExport(IExportList *parent, ELFSymbol *symbol)
+ : BaseExport(parent), symbol_(symbol), address_(0), type_(atNone)
+{
+ if (symbol_) {
+ address_ = symbol_->address();
+ name_ = symbol_->name();
+ }
+}
+
+ELFExport::ELFExport(IExportList *parent, const ELFExport &src)
+ : BaseExport(parent, src)
+{
+ address_ = src.address_;
+ name_ = src.name_;
+ symbol_ = src.symbol_;
+ type_ = src.type_;
+}
+
+ELFExport::~ELFExport()
+{
+ if (symbol_)
+ symbol_->set_bind(STB_LOCAL);
+}
+
+ELFExport *ELFExport::Clone(IExportList *parent) const
+{
+ ELFExport *exp = new ELFExport(parent, *this);
+ return exp;
+}
+
+std::string ELFExport::display_name(bool show_ret) const
+{
+ return DemangleName(name_).display_name(show_ret);
+}
+
+void ELFExport::Rebase(uint64_t delta_base)
+{
+ address_ += delta_base;
+}
+
+/**
+ * ELFExportList
+ */
+
+ELFExportList::ELFExportList(ELFArchitecture *owner)
+ : BaseExportList(owner)
+{
+
+}
+
+ELFExportList::ELFExportList(ELFArchitecture *owner, const ELFExportList &src)
+ : BaseExportList(owner, src)
+{
+
+}
+
+ELFExportList *ELFExportList::Clone(ELFArchitecture *owner) const
+{
+ ELFExportList *list = new ELFExportList(owner, *this);
+ return list;
+}
+
+ELFExport *ELFExportList::item(size_t index) const
+{
+ return reinterpret_cast<ELFExport *>(IExportList::item(index));
+}
+
+ELFExport *ELFExportList::Add(ELFSymbol *symbol)
+{
+ ELFExport *exp = new ELFExport(this, symbol);
+ AddObject(exp);
+ return exp;
+}
+
+IExport *ELFExportList::Add(uint64_t address)
+{
+ ELFExport *exp = new ELFExport(this, address);
+ AddObject(exp);
+ return exp;
+}
+
+void ELFExportList::ReadFromFile(ELFArchitecture &file)
+{
+ ELFSymbolList *symbol_list = file.dynsymbol_list();
+ for (size_t i = 0; i < symbol_list->count(); i++) {
+ ELFSymbol *symbol = symbol_list->item(i);
+ if (symbol->section_idx() && symbol->bind() == STB_GLOBAL && (symbol->type() == STT_FUNC || symbol->type() == STT_OBJECT))
+ Add(symbol);
+ }
+}
+
+ELFExport *ELFExportList::GetExportByAddress(uint64_t address) const
+{
+ return reinterpret_cast<ELFExport *>(BaseExportList::GetExportByAddress(address));
+}
+
+void ELFExportList::ReadFromBuffer(Buffer &buffer, IArchitecture &file)
+{
+ static const APIType export_function_types[] = {
+ atSetupImage,
+ atFreeImage,
+ atDecryptStringA,
+ atDecryptStringW,
+ atFreeString,
+ atSetSerialNumber,
+ atGetSerialNumberState,
+ atGetSerialNumberData,
+ atGetCurrentHWID,
+ atActivateLicense,
+ atDeactivateLicense,
+ atGetOfflineActivationString,
+ atGetOfflineDeactivationString,
+ atIsValidImageCRC,
+ atIsDebuggerPresent,
+ atIsVirtualMachinePresent,
+ atDecryptBuffer,
+ atIsProtected,
+ atCalcCRC,
+ atLoaderData,
+ atRuntimeInit
+ };
+
+ BaseExportList::ReadFromBuffer(buffer, file);
+
+ assert(count() == _countof(export_function_types));
+ for (size_t i = 0; i < count(); i++) {
+ item(i)->set_type(export_function_types[i]);
+ }
+}
+
+/**
+ * ELFSymbol
+ */
+
+ELFSymbol::ELFSymbol(ELFSymbolList *owner)
+ : ISymbol(), owner_(owner), address_(0), info_(STT_FUNC), other_(0), section_idx_(0), name_idx_(0), value_(0), size_(0),
+ is_deleted_(false), version_(0)
+{
+}
+
+ELFSymbol::ELFSymbol(ELFSymbolList *owner, const ELFSymbol &src)
+ : ISymbol(src), owner_(owner)
+{
+ address_ = src.address_;
+ name_ = src.name_;
+ info_ = src.info_;
+ other_ = src.other_;
+ section_idx_ = src.section_idx_;
+ name_idx_ = src.name_idx_;
+ value_ = src.value_;
+ size_ = src.size_;
+ is_deleted_ = src.is_deleted_;
+ version_ = src.version_;
+}
+
+ELFSymbol::~ELFSymbol()
+{
+ if (owner_)
+ owner_->RemoveObject(this);
+}
+
+ELFSymbol *ELFSymbol::Clone(ELFSymbolList *owner) const
+{
+ ELFSymbol *symbol = new ELFSymbol(owner, *this);
+ return symbol;
+}
+
+void ELFSymbol::ReadFromFile(ELFArchitecture &file, const ELFStringTable &strtab)
+{
+ if (file.cpu_address_size() == osDWord) {
+ Elf32_Sym hdr;
+ file.Read(&hdr, sizeof(hdr));
+ name_idx_ = hdr.st_name;
+ value_ = hdr.st_value;
+ size_ = hdr.st_size;
+ info_ = hdr.st_info;
+ other_ = hdr.st_other;
+ section_idx_ = hdr.st_shndx;
+ } else {
+ Elf64_Sym hdr;
+ file.Read(&hdr, sizeof(hdr));
+ name_idx_ = hdr.st_name;
+ value_ = hdr.st_value;
+ size_ = hdr.st_size;
+ info_ = hdr.st_info;
+ other_ = hdr.st_other;
+ section_idx_ = hdr.st_shndx;
+ }
+
+ name_ = strtab.GetString(name_idx_);
+
+ if (type() != STT_TLS && section_idx_)
+ address_ = value_;
+}
+
+size_t ELFSymbol::WriteToFile(ELFArchitecture &file, ELFStringTable &string_table)
+{
+ name_idx_ = string_table.AddString(name_);
+
+ size_t res;
+ if (file.cpu_address_size() == osDWord) {
+ Elf32_Sym hdr;
+ hdr.st_name = name_idx_;
+ hdr.st_value = static_cast<uint32_t>(value_);
+ hdr.st_size = static_cast<uint32_t>(size_);
+ hdr.st_info = info_;
+ hdr.st_other = other_;
+ hdr.st_shndx = section_idx_;
+ res = file.Write(&hdr, sizeof(hdr));
+ } else {
+ Elf64_Sym hdr;
+ hdr.st_name = name_idx_;
+ hdr.st_value = value_;
+ hdr.st_size = size_;
+ hdr.st_info = info_;
+ hdr.st_other = other_;
+ hdr.st_shndx = section_idx_;
+ res = file.Write(&hdr, sizeof(hdr));
+ }
+ return res;
+}
+
+void ELFSymbol::Rebase(uint64_t delta_base)
+{
+ if (address_)
+ address_ += delta_base;
+}
+
+std::string ELFSymbol::display_name(bool show_ret) const
+{
+ return DemangleName(name()).display_name(show_ret);
+}
+
+/**
+ * ELFSymbolList
+ */
+
+ELFSymbolList::ELFSymbolList(bool is_dynamic)
+ : ObjectList<ELFSymbol>(), is_dynamic_(is_dynamic)
+{
+
+}
+
+ELFSymbolList::ELFSymbolList(const ELFSymbolList &src)
+ : ObjectList<ELFSymbol>(src)
+{
+ is_dynamic_ = src.is_dynamic_;
+ for (size_t i = 0; i < src.count(); i++) {
+ AddObject(src.item(i)->Clone(this));
+ }
+}
+
+ELFSymbolList *ELFSymbolList::Clone() const
+{
+ ELFSymbolList *list = new ELFSymbolList(*this);
+ return list;
+}
+
+ELFSymbol *ELFSymbolList::Add()
+{
+ ELFSymbol *symbol = new ELFSymbol(this);
+ AddObject(symbol);
+ return symbol;
+}
+
+void ELFSymbolList::ReadFromFile(ELFArchitecture &file)
+{
+ if (is_dynamic_) {
+ ELFDirectory *dir = file.command_list()->GetCommandByType(DT_SYMTAB);
+ if (!dir)
+ return;
+
+ uint64_t entry_size = file.cpu_address_size() == osDWord ? sizeof(Elf32_Sym) : sizeof(Elf64_Sym);
+ uint64_t size;
+ ELFDirectory *hash = file.command_list()->GetCommandByType(DT_HASH);
+ if (hash) {
+ if (!file.AddressSeek(hash->value() + sizeof(uint32_t)))
+ throw std::runtime_error("Invalid format");
+ size = entry_size * file.ReadDWord();
+ }
+ else {
+ ELFDirectory *strtab = file.command_list()->GetCommandByType(DT_STRTAB);
+ if (!strtab)
+ throw std::runtime_error("Invalid format");
+ size = strtab->value() - dir->value();
+ }
+ if (!file.AddressSeek(dir->value()))
+ throw std::runtime_error("Invalid format");
+
+ for (uint64_t i = 0; i < size; i += entry_size) {
+ Add()->ReadFromFile(file, string_table_);
+ }
+
+ dir = file.command_list()->GetCommandByType(DT_VERSYM);
+ if (dir) {
+ if (!file.AddressSeek(dir->value()))
+ throw std::runtime_error("Invalid format");
+ for (size_t i = 0; i < count(); i++) {
+ item(i)->set_version(file.ReadWord());
+ }
+ }
+ }
+ else {
+ ELFSection *section = file.section_list()->GetSectionByType(SHT_SYMTAB);
+ if (!section)
+ return;
+
+ string_table_.ReadFromFile(file, *file.section_list()->item(section->link()));
+ file.Seek(section->physical_offset());
+ for (uint64_t i = 0; i < section->size(); i += section->entry_size()) {
+ Add()->ReadFromFile(file, string_table_);
+ }
+ }
+}
+
+static uint32_t elf_hash(const char *name)
+{
+ const unsigned char* nameu = reinterpret_cast<const unsigned char*>(name);
+ uint32_t h = 0;
+ unsigned char c;
+ while ((c = *nameu++) != '\0')
+ {
+ h = (h << 4) + c;
+ uint32_t g = h & 0xf0000000;
+ if (g != 0)
+ {
+ h ^= g >> 24;
+ h ^= g;
+ }
+ }
+ return h;
+}
+
+static uint32_t gnu_hash(const char *name)
+{
+ const unsigned char* nameu = reinterpret_cast<const unsigned char*>(name);
+ uint32_t h = 5381;
+ unsigned char c;
+ while ((c = *nameu++) != '\0')
+ h = (h << 5) + h + c;
+ return h;
+}
+
+static uint32_t compute_bucket_count(size_t symbol_count)
+{
+ static const uint32_t buckets[] =
+ {
+ 1, 3, 17, 37, 67, 97, 131, 197, 263, 521, 1031, 2053, 4099, 8209,
+ 16411, 32771, 65537, 131101, 262147
+ };
+
+ uint32_t ret = 1;
+ for (size_t i = 0; i < _countof(buckets); i++)
+ {
+ if (symbol_count < buckets[i])
+ break;
+ ret = buckets[i];
+ }
+ return ret;
+}
+
+size_t ELFSymbolList::WriteHash(ELFArchitecture &file)
+{
+ std::vector<ELFSymbol *> hashed_symbols;
+ std::vector<uint32_t> hashes;
+ size_t i;
+ ELFSymbol *symbol;
+
+ for (i = 0; i < count(); i++) {
+ symbol = item(i);
+ if (symbol->need_hash()) {
+ hashed_symbols.push_back(symbol);
+ hashes.push_back(elf_hash(symbol->name().c_str()));
+ }
+ }
+
+ uint32_t bucket_count = compute_bucket_count(hashed_symbols.size());
+
+ std::vector<uint32_t> buckets(bucket_count);
+ std::vector<uint32_t> chains(count());
+
+ for (i = 0; i < hashed_symbols.size(); i++) {
+ symbol = hashed_symbols[i];
+ uint32_t bucket = hashes[i] % bucket_count;
+ uint32_t index = static_cast<uint32_t>(IndexOf(symbol));
+ chains[index] = buckets[bucket];
+ buckets[bucket] = index;
+ }
+
+ file.WriteDWord(static_cast<uint32_t>(buckets.size()));
+ file.WriteDWord(static_cast<uint32_t>(chains.size()));
+ for (i = 0; i < buckets.size(); i++) {
+ file.WriteDWord(buckets[i]);
+ }
+ for (i = 0; i < chains.size(); i++) {
+ file.WriteDWord(chains[i]);
+ }
+ return (2 + buckets.size() + chains.size()) * sizeof(uint32_t);
+}
+
+template <typename T>
+size_t ELFSymbolList::WriteGNUHash(ELFArchitecture &file)
+{
+ std::vector<ELFSymbol *> hashed_symbols;
+ std::vector<ELFSymbol *> unhashed_symbols;
+ std::vector<uint32_t> hashes;
+ size_t i;
+ ELFSymbol *symbol;
+ std::map<size_t, ELFSymbol *> sym_index_map;
+
+ for (i = 0; i < count(); i++) {
+ symbol = item(i);
+ if (symbol->need_hash()) {
+ hashed_symbols.push_back(symbol);
+ hashes.push_back(gnu_hash(symbol->name().c_str()));
+ } else {
+ unhashed_symbols.push_back(symbol);
+ }
+ }
+
+ uint32_t symbol_base = 0;
+ for (i = 0; i < unhashed_symbols.size(); i++) {
+ symbol = unhashed_symbols[i];
+ RemoveObject(symbol);
+ InsertObject(symbol_base++, symbol);
+ }
+
+ size_t symbol_count = hashed_symbols.size();
+ uint32_t bucket_count = compute_bucket_count(symbol_count);
+
+ uint32_t maskbitslog2 = 1;
+ for (i = symbol_count >> 1; i != 0; i >>= 1)
+ ++maskbitslog2;
+ if (maskbitslog2 < 3)
+ maskbitslog2 = 5;
+ else if (((static_cast<size_t>(1U) << (maskbitslog2 - 2)) & symbol_count) != 0)
+ maskbitslog2 += 3;
+ else
+ maskbitslog2 += 2;
+
+ uint32_t shift1;
+ if (sizeof(T) == 4)
+ shift1 = 5;
+ else
+ {
+ if (maskbitslog2 == 5)
+ maskbitslog2 = 6;
+ shift1 = 6;
+ }
+ uint32_t mask = (1U << shift1) - 1U;
+ uint32_t shift2 = maskbitslog2;
+ uint32_t maskbits = 1U << maskbitslog2;
+ uint32_t maskwords = 1U << (maskbitslog2 - shift1);
+
+ std::vector<T> bitmask(maskwords);
+ std::vector<uint32_t> counts(bucket_count);
+ std::vector<uint32_t> indx(bucket_count);
+
+ for (i = 0; i < symbol_count; i++) {
+ ++counts[hashes[i] % bucket_count];
+ }
+ uint32_t cnt = symbol_base;
+ for (i = 0; i < bucket_count; ++i) {
+ indx[i] = cnt;
+ cnt += counts[i];
+ }
+ std::vector<uint32_t> buckets(bucket_count);
+ for (i = 0; i < bucket_count; i++) {
+ buckets[i] = counts[i] ? indx[i] : 0;
+ }
+ std::vector<uint32_t> chains(symbol_count);
+ for (i = 0; i < symbol_count; ++i)
+ {
+ symbol = hashed_symbols[i];
+ uint32_t hashval = hashes[i];
+
+ uint32_t bucket = hashval % bucket_count;
+ uint32_t val = ((hashval >> shift1) & ((maskbits >> shift1) - 1));
+ bitmask[val] |= (static_cast<T>(1U)) << (hashval & mask);
+ bitmask[val] |= (static_cast<T>(1U)) << ((hashval >> shift2) & mask);
+ val = hashval & ~ 1U;
+ if (counts[bucket] == 1)
+ val |= 1;
+ chains[indx[bucket] - symbol_base] = val;
+ --counts[bucket];
+ sym_index_map[indx[bucket]] = symbol;
+ ++indx[bucket];
+ }
+
+ for (std::map<size_t, ELFSymbol*>::const_iterator it = sym_index_map.begin(); it != sym_index_map.end(); it++) {
+ i = it->first;
+ symbol = it->second;
+ if (item(i) != symbol) {
+ RemoveObject(symbol);
+ InsertObject(i, symbol);
+ }
+ }
+
+ file.WriteDWord(bucket_count);
+ file.WriteDWord(symbol_base);
+ file.WriteDWord(maskwords);
+ file.WriteDWord(shift2);
+ for (i = 0; i < maskwords; i++) {
+ file.Write(&bitmask[i], sizeof(bitmask[i]));
+ }
+ for (i = 0; i < bucket_count; i++) {
+ file.WriteDWord(buckets[i]);
+ }
+ for (i = 0; i < symbol_count; i++) {
+ file.WriteDWord(chains[i]);
+ }
+ return (4 + bucket_count + symbol_count) * sizeof(uint32_t) + maskbits / 8;
+}
+
+size_t ELFSymbolList::WriteVersym(ELFArchitecture &file)
+{
+ size_t res = 0;
+ for (size_t i = 0; i < count(); i++) {
+ res += file.WriteWord(item(i)->version());
+ }
+ return res;
+}
+
+void ELFSymbolList::WriteToFile(ELFArchitecture &file)
+{
+ uint64_t pos;
+ uint64_t address;
+ size_t size;
+ ELFSection *section;
+
+ string_table_.clear();
+
+ if (is_dynamic_) {
+ ELFDirectory *symtab = file.command_list()->GetCommandByType(DT_SYMTAB);
+ if (!symtab)
+ return;
+
+ ELFDirectory *hash = file.command_list()->GetCommandByType(DT_GNU_HASH);
+ if (hash) {
+ section = file.section_list()->GetSectionByType(SHT_GNU_HASH);
+ pos = (section && section->alignment() > 1) ? file.Resize(AlignValue(file.Tell(), section->alignment())) : file.Tell();
+ address = file.AddressTell();
+ size = (file.cpu_address_size() == osDWord) ? WriteGNUHash<uint32_t>(file) : WriteGNUHash<uint64_t>(file);
+ hash->set_value(address);
+
+ if (section) {
+ section->Rebase(address - section->address());
+ section->set_physical_offset(static_cast<uint32_t>(pos));
+ section->set_size(static_cast<uint32_t>(size));
+ }
+ }
+
+ hash = file.command_list()->GetCommandByType(DT_HASH);
+ if (hash) {
+ section = file.section_list()->GetSectionByType(SHT_HASH);
+ pos = (section && section->alignment() > 1) ? file.Resize(AlignValue(file.Tell(), section->alignment())) : file.Tell();
+ address = file.AddressTell();
+ size = WriteHash(file);
+ hash->set_value(address);
+
+ if (section) {
+ section->Rebase(address - section->address());
+ section->set_physical_offset(static_cast<uint32_t>(pos));
+ section->set_size(static_cast<uint32_t>(size));
+ }
+ }
+
+ section = file.section_list()->GetSectionByType(SHT_DYNSYM);
+ pos = (section && section->alignment() > 1) ? file.Resize(AlignValue(file.Tell(), section->alignment())) : file.Tell();
+ address = file.AddressTell();
+ size = 0;
+ for (size_t i = 0; i < count(); i++) {
+ size += item(i)->WriteToFile(file, string_table_);
+ }
+ symtab->set_value(address);
+
+ if (section) {
+ if (section->address())
+ section->Rebase(address - section->address());
+ section->set_physical_offset(static_cast<uint32_t>(pos));
+ section->set_size(static_cast<uint32_t>(size));
+ }
+
+ file.command_list()->WriteStrings(string_table_);
+ file.verdef_list()->WriteStrings(string_table_);
+ file.verneed_list()->WriteStrings(string_table_);
+
+ pos = file.Tell();
+ address = file.AddressTell();
+ size = string_table_.WriteToFile(file);
+
+ if (section) {
+ section = file.section_list()->item(section->link());
+ if (section->address())
+ section->Rebase(address - section->address());
+ section->set_physical_offset(static_cast<uint32_t>(pos));
+ section->set_size(static_cast<uint32_t>(size));
+ }
+
+ ELFDirectory *dir = file.command_list()->GetCommandByType(DT_STRTAB);
+ if (!dir)
+ dir = file.command_list()->Add(DT_STRTAB);
+ dir->set_value(address);
+
+ dir = file.command_list()->GetCommandByType(DT_STRSZ);
+ if (!dir)
+ dir = file.command_list()->Add(DT_STRSZ);
+ dir->set_value(static_cast<uint32_t>(size));
+
+ dir = file.command_list()->GetCommandByType(DT_VERSYM);
+ if (dir) {
+ section = file.section_list()->GetSectionByType(SHT_GNU_versym);
+ pos = (section && section->alignment() > 1) ? file.Resize(AlignValue(file.Tell(), section->alignment())) : file.Tell();
+ address = file.AddressTell();
+ size = WriteVersym(file);
+ dir->set_value(address);
+
+ if (section) {
+ section->Rebase(address - section->address());
+ section->set_physical_offset(static_cast<uint32_t>(pos));
+ section->set_size(static_cast<uint32_t>(size));
+ }
+ }
+ }
+ else {
+ ELFSection *section = file.section_list()->GetSectionByType(SHT_SYMTAB);
+ if (!section)
+ return;
+
+ pos = section->alignment() > 1 ? file.Resize(AlignValue(file.Tell(), section->alignment())) : file.Tell();
+ address = file.AddressTell();
+ size = 0;
+ for (size_t i = 0; i < count(); i++) {
+ size += item(i)->WriteToFile(file, string_table_);
+ }
+ if (section->address())
+ section->Rebase(address - section->address());
+ section->set_physical_offset(static_cast<uint32_t>(pos));
+ section->set_size(static_cast<uint32_t>(size));
+
+ pos = file.Tell();
+ address = file.AddressTell();
+ size = string_table_.WriteToFile(file);
+ section = file.section_list()->item(section->link());
+ if (section->address())
+ section->Rebase(address - section->address());
+ section->set_physical_offset(static_cast<uint32_t>(pos));
+ section->set_size(static_cast<uint32_t>(size));
+ }
+}
+
+void ELFSymbolList::Pack()
+{
+ for (size_t i = count(); i > 0 ; i--) {
+ ELFSymbol *symbol = item(i - 1);
+ if (symbol->is_deleted())
+ delete symbol;
+ }
+}
+
+void ELFSymbolList::Rebase(uint64_t delta_base)
+{
+ for (size_t i = 0; i < count(); i++) {
+ item(i)->Rebase(delta_base);
+ }
+}
+
+/**
+ * ELFVernaux
+ */
+
+ELFVernaux::ELFVernaux(ELFVerneed *owner)
+ : IObject(), owner_(owner), hash_(0), flags_(0), other_(0), next_(0), name_pos_(0)
+{
+
+}
+
+ELFVernaux::ELFVernaux(ELFVerneed *owner, const ELFVernaux &src)
+ : IObject(), owner_(owner), next_(0), name_pos_(0)
+{
+ hash_ = src.hash_;
+ flags_ = src.flags_;
+ other_ = src.other_;
+ name_ = src.name_;
+}
+
+ELFVernaux::~ELFVernaux()
+{
+ if (owner_)
+ owner_->RemoveObject(this);
+}
+
+ELFVernaux *ELFVernaux::Clone(ELFVerneed *owner) const
+{
+ ELFVernaux *vernaux = new ELFVernaux(owner, *this);
+ return vernaux;
+}
+
+void ELFVernaux::ReadFromFile(ELFArchitecture &file)
+{
+ if (file.cpu_address_size() == osDWord) {
+ Elf32_Vernaux vernaux;
+ file.Read(&vernaux, sizeof(vernaux));
+ hash_ = vernaux.vna_hash;
+ flags_ = vernaux.vna_flags;
+ other_ = vernaux.vna_other;
+ name_ = file.dynsymbol_list()->string_table()->GetString(vernaux.vna_name);
+ next_ = vernaux.vna_next;
+ } else {
+ Elf64_Vernaux vernaux;
+ file.Read(&vernaux, sizeof(vernaux));
+ hash_ = vernaux.vna_hash;
+ flags_ = vernaux.vna_flags;
+ other_ = vernaux.vna_other;
+ name_ = file.dynsymbol_list()->string_table()->GetString(vernaux.vna_name);
+ next_ = vernaux.vna_next;
+ }
+}
+
+size_t ELFVernaux::WriteToFile(ELFArchitecture &file)
+{
+ size_t res;
+ if (file.cpu_address_size() == osDWord) {
+ Elf32_Vernaux vernaux;
+ vernaux.vna_hash = hash_;
+ vernaux.vna_flags = flags_;
+ vernaux.vna_other = other_;
+ vernaux.vna_name = name_pos_;
+ vernaux.vna_next = (owner_ && owner_->last() != this) ? sizeof(vernaux) : 0;
+ res = file.Write(&vernaux, sizeof(vernaux));
+ } else {
+ Elf64_Vernaux vernaux;
+ vernaux.vna_hash = hash_;
+ vernaux.vna_flags = flags_;
+ vernaux.vna_other = other_;
+ vernaux.vna_name = name_pos_;
+ vernaux.vna_next = (owner_ && owner_->last() != this) ? sizeof(vernaux) : 0;
+ res = file.Write(&vernaux, sizeof(vernaux));
+ }
+ return res;
+}
+
+void ELFVernaux::WriteStrings(ELFStringTable &string_table)
+{
+ name_pos_ = string_table.AddString(name_);
+}
+
+/**
+ * ELFVerneed
+ */
+
+ELFVerneed::ELFVerneed(ELFVerneedList *owner)
+ : ObjectList<ELFVernaux>(), owner_(owner), version_(0), next_(0), file_pos_(0)
+{
+
+}
+
+ELFVerneed::ELFVerneed(ELFVerneedList *owner, const ELFVerneed &src)
+ : ObjectList<ELFVernaux>(src), owner_(owner), next_(0), file_pos_(0)
+{
+ version_ = src.version_;
+ file_ = src.file_;
+ for (size_t i = 0; i < src.count(); i++) {
+ AddObject(src.item(i)->Clone(this));
+ }
+}
+
+ELFVerneed::~ELFVerneed()
+{
+ if (owner_)
+ owner_->RemoveObject(this);
+}
+
+ELFVerneed *ELFVerneed::Clone(ELFVerneedList *owner) const
+{
+ ELFVerneed *verneed = new ELFVerneed(owner, *this);
+ return verneed;
+}
+
+ELFVernaux *ELFVerneed::Add()
+{
+ ELFVernaux *vernaux = new ELFVernaux(this);
+ AddObject(vernaux);
+ return vernaux;
+}
+
+void ELFVerneed::ReadFromFile(ELFArchitecture &file)
+{
+ uint64_t pos = file.Tell();
+ size_t count;
+ uint32_t offset;
+ if (file.cpu_address_size() == osDWord) {
+ Elf32_Verneed verneed;
+ file.Read(&verneed, sizeof(verneed));
+ version_ = verneed.vn_version;
+ count = verneed.vn_cnt;
+ file_ = file.dynsymbol_list()->string_table()->GetString(verneed.vn_file);
+ offset = verneed.vn_aux;
+ next_ = verneed.vn_next;
+ } else {
+ Elf64_Verneed verneed;
+ file.Read(&verneed, sizeof(verneed));
+ version_ = verneed.vn_version;
+ count = verneed.vn_cnt;
+ file_ = file.dynsymbol_list()->string_table()->GetString(verneed.vn_file);
+ offset = verneed.vn_aux;
+ next_ = verneed.vn_next;
+ }
+
+ for (size_t i = 0; i < count; i++) {
+ file.Seek(pos + offset);
+ ELFVernaux *vernaux = Add();
+ vernaux->ReadFromFile(file);
+ if (!vernaux->next())
+ break;
+
+ offset += vernaux->next();
+ }
+}
+
+size_t ELFVerneed::WriteToFile(ELFArchitecture &file)
+{
+ size_t res;
+ if (file.cpu_address_size() == osDWord) {
+ Elf32_Verneed verneed;
+ verneed.vn_version = version_;
+ verneed.vn_cnt = static_cast<uint16_t>(count());
+ verneed.vn_file = file_pos_;
+ verneed.vn_aux = sizeof(verneed);
+ verneed.vn_next = (owner_ && owner_->last() != this) ? static_cast<uint32_t>(sizeof(Elf32_Verneed) + count() * sizeof(Elf32_Vernaux)) : 0;
+ res = file.Write(&verneed, sizeof(verneed));
+ } else {
+ Elf64_Verneed verneed;
+ verneed.vn_version = version_;
+ verneed.vn_cnt = static_cast<uint16_t>(count());
+ verneed.vn_file = file_pos_;
+ verneed.vn_aux = sizeof(verneed);
+ verneed.vn_next = (owner_ && owner_->last() != this) ? static_cast<uint32_t>(sizeof(Elf64_Verneed) + count() * sizeof(Elf64_Vernaux)) : 0;
+ res = file.Write(&verneed, sizeof(verneed));
+ }
+
+ for (size_t i = 0; i < count(); i++) {
+ res += item(i)->WriteToFile(file);
+ }
+ return res;
+}
+
+void ELFVerneed::WriteStrings(ELFStringTable &string_table)
+{
+ file_pos_ = string_table.AddString(file_);
+ for (size_t i = 0; i < count(); i++) {
+ item(i)->WriteStrings(string_table);
+ }
+}
+
+ELFVernaux *ELFVerneed::GetVernaux(uint32_t hash) const
+{
+ for (size_t i = 0; i < count(); i++) {
+ ELFVernaux *res = item(i);
+ if (res->hash() == hash)
+ return res;
+ }
+ return NULL;
+}
+
+/**
+ * ELFVerneedList
+ */
+
+ELFVerneedList::ELFVerneedList()
+ : ObjectList<ELFVerneed>()
+{
+
+}
+
+ELFVerneedList::ELFVerneedList(const ELFVerneedList &src)
+ : ObjectList<ELFVerneed>(src)
+{
+ for (size_t i = 0; i < src.count(); i++) {
+ AddObject(src.item(i)->Clone(this));
+ }
+}
+
+ELFVerneedList *ELFVerneedList::Clone() const
+{
+ ELFVerneedList *list = new ELFVerneedList(*this);
+ return list;
+}
+
+ELFVerneed *ELFVerneedList::Add()
+{
+ ELFVerneed *verneed = new ELFVerneed(this);
+ AddObject(verneed);
+ return verneed;
+}
+
+void ELFVerneedList::ReadFromFile(ELFArchitecture &file)
+{
+ ELFDirectory *dir = file.command_list()->GetCommandByType(DT_VERNEED);
+ if (!dir)
+ return;
+
+ ELFDirectory *num = file.command_list()->GetCommandByType(DT_VERNEEDNUM);
+ if (!num || !file.AddressSeek(dir->value()))
+ throw std::runtime_error("Invalid format");
+
+ uint32_t offset = 0;
+ uint64_t pos = file.Tell();
+ for (uint64_t i = 0; i < num->value(); i++) {
+ file.Seek(pos + offset);
+
+ ELFVerneed *verneed = Add();
+ verneed->ReadFromFile(file);
+ if (!verneed->next())
+ break;
+
+ offset += verneed->next();
+ }
+}
+
+void ELFVerneedList::WriteToFile(ELFArchitecture &file)
+{
+ ELFDirectory *dir = file.command_list()->GetCommandByType(DT_VERNEED);
+ if (!dir)
+ return;
+
+ ELFDirectory *num = file.command_list()->GetCommandByType(DT_VERNEEDNUM);
+ if (!num)
+ num = file.command_list()->Add(DT_VERNEEDNUM);
+
+ ELFSection *section = file.section_list()->GetSectionByType(SHT_GNU_verneed);
+
+ size_t i;
+ uint64_t pos = (section && section->alignment() > 1) ? file.Resize(AlignValue(file.Tell(), section->alignment())) : file.Tell();
+ uint64_t address = file.AddressTell();
+ size_t size = 0;
+ for (i = 0; i < count(); i++) {
+ size += item(i)->WriteToFile(file);
+ }
+ dir->set_value(address);
+ num->set_value(count());
+
+ if (section) {
+ if (section->address())
+ section->Rebase(address - section->address());
+ section->set_physical_offset(static_cast<uint32_t>(pos));
+ section->set_size(static_cast<uint32_t>(size));
+ section->set_info(static_cast<uint32_t>(count()));
+ }
+}
+
+void ELFVerneedList::WriteStrings(ELFStringTable &string_table)
+{
+ for (size_t i = 0; i < count(); i++) {
+ item(i)->WriteStrings(string_table);
+ }
+}
+
+ELFVerneed *ELFVerneedList::GetVerneed(const std::string &name) const
+{
+ for (size_t i = 0; i < count(); i++) {
+ ELFVerneed *verneed = item(i);
+ if (verneed->file() == name)
+ return verneed;
+ }
+ return NULL;
+}
+
+/**
+* ELFVerdaux
+*/
+
+ELFVerdaux::ELFVerdaux(ELFVerdef *owner)
+ : IObject(), owner_(owner), next_(0), name_pos_(0)
+{
+
+}
+
+ELFVerdaux::ELFVerdaux(ELFVerdef *owner, const ELFVerdaux &src)
+ : IObject(), owner_(owner), next_(0), name_pos_(0)
+{
+ name_ = src.name_;
+}
+
+ELFVerdaux::~ELFVerdaux()
+{
+ if (owner_)
+ owner_->RemoveObject(this);
+}
+
+ELFVerdaux *ELFVerdaux::Clone(ELFVerdef *owner) const
+{
+ ELFVerdaux *verdaux = new ELFVerdaux(owner, *this);
+ return verdaux;
+}
+
+void ELFVerdaux::ReadFromFile(ELFArchitecture &file)
+{
+ if (file.cpu_address_size() == osDWord) {
+ Elf32_Verdaux verdaux;
+ file.Read(&verdaux, sizeof(verdaux));
+ name_ = file.dynsymbol_list()->string_table()->GetString(verdaux.vda_name);
+ next_ = verdaux.vda_next;
+ }
+ else {
+ Elf64_Verdaux verdaux;
+ file.Read(&verdaux, sizeof(verdaux));
+ name_ = file.dynsymbol_list()->string_table()->GetString(verdaux.vda_name);
+ next_ = verdaux.vda_next;
+ }
+}
+
+size_t ELFVerdaux::WriteToFile(ELFArchitecture &file)
+{
+ size_t res;
+ if (file.cpu_address_size() == osDWord) {
+ Elf32_Verdaux verdaux;
+ verdaux.vda_name = name_pos_;
+ verdaux.vda_next = (owner_ && owner_->last() != this) ? sizeof(verdaux) : 0;
+ res = file.Write(&verdaux, sizeof(verdaux));
+ }
+ else {
+ Elf64_Verdaux verdaux;
+ verdaux.vda_name = name_pos_;
+ verdaux.vda_next = (owner_ && owner_->last() != this) ? sizeof(verdaux) : 0;
+ res = file.Write(&verdaux, sizeof(verdaux));
+ }
+ return res;
+}
+
+void ELFVerdaux::WriteStrings(ELFStringTable &string_table)
+{
+ name_pos_ = string_table.AddString(name_);
+}
+
+/**
+* ELFVerdef
+*/
+
+ELFVerdef::ELFVerdef(ELFVerdefList *owner)
+ : ObjectList<ELFVerdaux>(), owner_(owner), version_(0), next_(0), flags_(0), ndx_(0), hash_(0)
+{
+
+}
+
+ELFVerdef::ELFVerdef(ELFVerdefList *owner, const ELFVerdef &src)
+ : ObjectList<ELFVerdaux>(src), owner_(owner), next_(0)
+{
+ version_ = src.version_;
+ flags_ = src.flags_;
+ ndx_ = src.ndx_;
+ hash_ = src.hash_;
+ for (size_t i = 0; i < src.count(); i++) {
+ AddObject(src.item(i)->Clone(this));
+ }
+}
+
+ELFVerdef::~ELFVerdef()
+{
+ if (owner_)
+ owner_->RemoveObject(this);
+}
+
+ELFVerdef *ELFVerdef::Clone(ELFVerdefList *owner) const
+{
+ ELFVerdef *verdef = new ELFVerdef(owner, *this);
+ return verdef;
+}
+
+ELFVerdaux *ELFVerdef::Add()
+{
+ ELFVerdaux *verdaux = new ELFVerdaux(this);
+ AddObject(verdaux);
+ return verdaux;
+}
+
+void ELFVerdef::ReadFromFile(ELFArchitecture &file)
+{
+ uint64_t pos = file.Tell();
+ size_t count;
+ uint32_t offset;
+ if (file.cpu_address_size() == osDWord) {
+ Elf32_Verdef verdef;
+ file.Read(&verdef, sizeof(verdef));
+ version_ = verdef.vd_version;
+ flags_ = verdef.vd_flags;
+ ndx_ = verdef.vd_ndx;
+ hash_ = verdef.vd_hash;
+ count = verdef.vd_cnt;
+ offset = verdef.vd_aux;
+ next_ = verdef.vd_next;
+ }
+ else {
+ Elf64_Verdef verdef;
+ file.Read(&verdef, sizeof(verdef));
+ version_ = verdef.vd_version;
+ flags_ = verdef.vd_flags;
+ ndx_ = verdef.vd_ndx;
+ hash_ = verdef.vd_hash;
+ count = verdef.vd_cnt;
+ offset = verdef.vd_aux;
+ next_ = verdef.vd_next;
+ }
+
+ for (size_t i = 0; i < count; i++) {
+ file.Seek(pos + offset);
+ ELFVerdaux *verdaux = Add();
+ verdaux->ReadFromFile(file);
+ if (!verdaux->next())
+ break;
+
+ offset += verdaux->next();
+ }
+}
+
+size_t ELFVerdef::WriteToFile(ELFArchitecture &file)
+{
+ size_t res;
+ if (file.cpu_address_size() == osDWord) {
+ Elf32_Verdef verdef;
+ verdef.vd_version = version_;
+ verdef.vd_flags = flags_;
+ verdef.vd_ndx = ndx_;
+ verdef.vd_hash = hash_;
+ verdef.vd_cnt = static_cast<uint16_t>(count());
+ verdef.vd_aux = sizeof(verdef);
+ verdef.vd_next = (owner_ && owner_->last() != this) ? static_cast<uint32_t>(sizeof(Elf32_Verdef) + count() * sizeof(Elf32_Verdaux)) : 0;
+ res = file.Write(&verdef, sizeof(verdef));
+ }
+ else {
+ Elf64_Verdef verdef;
+ verdef.vd_version = version_;
+ verdef.vd_flags = flags_;
+ verdef.vd_ndx = ndx_;
+ verdef.vd_hash = hash_;
+ verdef.vd_cnt = static_cast<uint16_t>(count());
+ verdef.vd_aux = sizeof(verdef);
+ verdef.vd_next = (owner_ && owner_->last() != this) ? static_cast<uint32_t>(sizeof(Elf64_Verdef) + count() * sizeof(Elf64_Verdaux)) : 0;
+ res = file.Write(&verdef, sizeof(verdef));
+ }
+
+ for (size_t i = 0; i < count(); i++) {
+ res += item(i)->WriteToFile(file);
+ }
+ return res;
+}
+
+void ELFVerdef::WriteStrings(ELFStringTable &string_table)
+{
+ for (size_t i = 0; i < count(); i++) {
+ item(i)->WriteStrings(string_table);
+ }
+}
+
+/**
+* ELFVerdefList
+*/
+
+ELFVerdefList::ELFVerdefList()
+ : ObjectList<ELFVerdef>()
+{
+
+}
+
+ELFVerdefList::ELFVerdefList(const ELFVerdefList &src)
+ : ObjectList<ELFVerdef>(src)
+{
+ for (size_t i = 0; i < src.count(); i++) {
+ AddObject(src.item(i)->Clone(this));
+ }
+}
+
+ELFVerdefList *ELFVerdefList::Clone() const
+{
+ ELFVerdefList *list = new ELFVerdefList(*this);
+ return list;
+}
+
+ELFVerdef *ELFVerdefList::Add()
+{
+ ELFVerdef *verdef = new ELFVerdef(this);
+ AddObject(verdef);
+ return verdef;
+}
+
+void ELFVerdefList::ReadFromFile(ELFArchitecture &file)
+{
+ ELFDirectory *dir = file.command_list()->GetCommandByType(DT_VERDEF);
+ if (!dir)
+ return;
+
+ ELFDirectory *num = file.command_list()->GetCommandByType(DT_VERDEFNUM);
+ if (!num || !file.AddressSeek(dir->value()))
+ throw std::runtime_error("Invalid format");
+
+ uint32_t offset = 0;
+ uint64_t pos = file.Tell();
+ for (uint64_t i = 0; i < num->value(); i++) {
+ file.Seek(pos + offset);
+
+ ELFVerdef *verdef = Add();
+ verdef->ReadFromFile(file);
+ if (!verdef->next())
+ break;
+
+ offset += verdef->next();
+ }
+}
+
+void ELFVerdefList::WriteToFile(ELFArchitecture &file)
+{
+ ELFDirectory *dir = file.command_list()->GetCommandByType(DT_VERDEF);
+ if (!dir)
+ return;
+
+ ELFDirectory *num = file.command_list()->GetCommandByType(DT_VERDEFNUM);
+ if (!num)
+ num = file.command_list()->Add(DT_VERDEFNUM);
+
+ ELFSection *section = file.section_list()->GetSectionByType(SHT_GNU_verdef);
+
+ size_t i;
+ uint64_t pos = (section && section->alignment() > 1) ? file.Resize(AlignValue(file.Tell(), section->alignment())) : file.Tell();
+ uint64_t address = file.AddressTell();
+ size_t size = 0;
+ for (i = 0; i < count(); i++) {
+ size += item(i)->WriteToFile(file);
+ }
+ dir->set_value(address);
+ num->set_value(count());
+
+ if (section) {
+ if (section->address())
+ section->Rebase(address - section->address());
+ section->set_physical_offset(static_cast<uint32_t>(pos));
+ section->set_size(static_cast<uint32_t>(size));
+ section->set_info(static_cast<uint32_t>(count()));
+ }
+}
+
+void ELFVerdefList::WriteStrings(ELFStringTable &string_table)
+{
+ for (size_t i = 0; i < count(); i++) {
+ item(i)->WriteStrings(string_table);
+ }
+}
+
+/**
+ * ELFRelocation
+ */
+
+ELFRelocation::ELFRelocation(ELFRelocationList *owner, bool is_rela, uint64_t address, OperandSize size, uint32_t type, ELFSymbol *symbol, uint64_t addend)
+ : BaseRelocation(owner, address, size), is_rela_(is_rela), type_(type), symbol_(symbol), addend_(addend), value_(0)
+{
+
+}
+
+ELFRelocation::ELFRelocation(ELFRelocationList *owner, const ELFRelocation &src)
+ : BaseRelocation(owner, src)
+{
+ is_rela_ = src.is_rela_;
+ type_ = src.type_;
+ symbol_ = src.symbol_;
+ addend_ = src.addend_;
+ value_ = src.value_;
+}
+
+ELFRelocation *ELFRelocation::Clone(IRelocationList *owner) const
+{
+ ELFRelocation *relocation = new ELFRelocation(reinterpret_cast<ELFRelocationList*>(owner), *this);
+ return relocation;
+}
+
+size_t ELFRelocation::WriteToFile(ELFArchitecture &file)
+{
+ size_t res = 0;
+ if (file.cpu_address_size() == osDWord) {
+ Elf32_Rel rel;
+ rel.r_offset = static_cast<uint32_t>(address());
+ rel.r_info = (static_cast<uint32_t>(file.dynsymbol_list()->IndexOf(symbol_)) << 8) | type_;
+ res += file.Write(&rel, sizeof(rel));
+ if (is_rela_)
+ res += file.WriteDWord(static_cast<uint32_t>(addend_));
+ } else {
+ Elf64_Rel rel;
+ rel.r_offset = address();
+ rel.r_type = type_;
+ rel.r_ssym = static_cast<uint32_t>(file.dynsymbol_list()->IndexOf(symbol_));
+ res += file.Write(&rel, sizeof(rel));
+ if (is_rela_)
+ res += file.WriteQWord(addend_);
+ }
+ return res;
+}
+
+void ELFRelocation::Rebase(IArchitecture &file, uint64_t delta_base)
+{
+ if (!file.AddressSeek(address()))
+ return;
+
+ uint64_t value;
+ uint64_t pos = file.Tell();
+ size_t value_size = OperandSizeToValue(file.cpu_address_size());
+ switch (type_) {
+ case R_386_JMP_SLOT:
+ value = 0;
+ file.Read(&value, value_size);
+ if (value) {
+ value += delta_base;
+ file.Seek(pos);
+ file.Write(&value, value_size);
+ }
+ break;
+ case R_386_RELATIVE:
+ if (is_rela_) {
+ value = addend_;
+ } else {
+ value = 0;
+ file.Read(&value, value_size);
+ file.Seek(pos);
+ }
+ value += delta_base;
+ file.Write(&value, value_size);
+ break;
+ }
+
+ BaseRelocation::Rebase(file, delta_base);
+}
+
+/**
+ * ELFRelocationList
+ */
+
+ELFRelocationList::ELFRelocationList()
+ : BaseRelocationList()
+{
+
+}
+
+ELFRelocationList::ELFRelocationList(const ELFRelocationList &src)
+ : BaseRelocationList(src)
+{
+
+}
+
+ELFRelocationList *ELFRelocationList::Clone() const
+{
+ ELFRelocationList *list = new ELFRelocationList(*this);
+ return list;
+}
+
+ELFRelocation *ELFRelocationList::item(size_t index) const
+{
+ return reinterpret_cast<ELFRelocation *>(BaseRelocationList::item(index));
+}
+
+ELFRelocation *ELFRelocationList::GetRelocationByAddress(uint64_t address) const
+{
+ return reinterpret_cast<ELFRelocation *>(BaseRelocationList::GetRelocationByAddress(address));
+}
+
+ELFRelocation *ELFRelocationList::Add(bool is_rela, uint64_t address, OperandSize size, uint32_t type, ELFSymbol *symbol, uint64_t addend)
+{
+ ELFRelocation *relocation = new ELFRelocation(this, is_rela, address, size, type, symbol, addend);
+ AddObject(relocation);
+ return relocation;
+}
+
+void ELFRelocationList::ReadFromFile(ELFArchitecture &file)
+{
+ const uint32_t dir_types[3][2] = {{DT_REL, DT_RELSZ}, {DT_RELA, DT_RELASZ}, {DT_JMPREL, DT_PLTRELSZ}};
+ ELFDirectory *plt_rel = file.command_list()->GetCommandByType(DT_PLTREL);
+
+ size_t i;
+ OperandSize cpu_address_size = file.cpu_address_size();
+ for (i = 0; i < _countof(dir_types); i++) {
+ ELFDirectory *dir = file.command_list()->GetCommandByType(dir_types[i][0]);
+ if (!dir)
+ continue;
+
+ ELFDirectory *sz = file.command_list()->GetCommandByType(dir_types[i][1]);
+ if (!sz || !file.AddressSeek(dir->value()))
+ throw std::runtime_error("Invalid format");
+
+ size_t entry_size;
+ bool is_rela;
+ if (dir->type() == DT_JMPREL) {
+ if (!plt_rel)
+ throw std::runtime_error("Invalid format");
+ is_rela = (plt_rel->value() == DT_RELA);
+ } else
+ is_rela = (dir->type() == DT_RELA);
+ if (is_rela)
+ entry_size = file.cpu_address_size() == osDWord ? sizeof(Elf32_Rela) : sizeof(Elf64_Rela);
+ else
+ entry_size = file.cpu_address_size() == osDWord ? sizeof(Elf32_Rel) : sizeof(Elf64_Rel);
+ for (uint64_t j = 0; j < sz->value(); j += entry_size) {
+ uint64_t address;
+ uint32_t type;
+ ELFSymbol *symbol;
+ uint64_t addend = 0;
+ if (cpu_address_size == osDWord) {
+ Elf32_Rel rel;
+ file.Read(&rel, sizeof(rel));
+ address = rel.r_offset;
+ type = static_cast<uint8_t>(rel.r_info);
+ symbol = (type == R_386_IRELATIVE) ? NULL : file.dynsymbol_list()->item(rel.r_info >> 8);
+ if (is_rela)
+ addend = file.ReadDWord();
+ } else {
+ Elf64_Rel rel;
+ file.Read(&rel, sizeof(rel));
+ address = rel.r_offset;
+ type = rel.r_type;
+ symbol = (type == R_X86_64_IRELATIVE) ? NULL : file.dynsymbol_list()->item(rel.r_ssym);
+ if (is_rela)
+ addend = file.ReadQWord();
+ }
+ if (type == R_386_RELATIVE)
+ file.fixup_list()->Add(address, cpu_address_size);
+ else
+ Add(is_rela, address, cpu_address_size, type, symbol, addend);
+ }
+ }
+
+ if (cpu_address_size == osDWord) {
+ for (i = 0; i < count(); i++) {
+ ELFRelocation *reloc = item(i);
+ if (file.AddressSeek(reloc->address())) {
+ switch (reloc->size()) {
+ case osDWord:
+ reloc->set_value(file.ReadDWord());
+ break;
+ case osQWord:
+ reloc->set_value(file.ReadQWord());
+ break;
+ }
+ }
+ }
+ }
+}
+
+void ELFRelocationList::WriteToFile(ELFArchitecture &file)
+{
+ size_t i, j, k;
+ ELFRelocation *reloc;
+ ELFDirectory *dir;
+ std::vector<ELFRelocation *> reloc_list[3];
+ ELFSection *section_list[3] = {};
+ const uint32_t dir_types[3][2] = {{DT_REL, DT_RELSZ}, {DT_RELA, DT_RELASZ}, {DT_JMPREL, DT_PLTRELSZ}};
+ const uint32_t rel_dir_types[2] = {DT_RELCOUNT, DT_RELACOUNT};
+
+ for (i = 0; i < count(); i++) {
+ reloc = item(i);
+ if (reloc->type() == R_386_JMP_SLOT)
+ j = 2;
+ else
+ j = reloc->is_rela() ? 1 : 0;
+ reloc_list[j].push_back(reloc);
+ }
+
+ if (file.fixup_list()->count()) {
+ // convert fixups into relocations
+ std::vector<ELFRelocation *> fixup_list;
+ uint64_t pos = file.Tell();
+ bool is_rela = reloc_list[1].size() > 0;
+ for (i = 0; i < file.fixup_list()->count(); i++) {
+ ELFFixup *fixup = file.fixup_list()->item(i);
+ uint64_t addend = 0;
+ if (is_rela && file.AddressSeek(fixup->address()))
+ addend = (file.cpu_address_size() == osDWord) ? file.ReadDWord() : file.ReadQWord();
+ reloc = Add(is_rela, fixup->address(), file.cpu_address_size(), R_386_RELATIVE, file.dynsymbol_list()->item(0), addend);
+ fixup_list.push_back(reloc);
+ }
+ file.Seek(pos);
+ j = is_rela ? 1 : 0;
+ reloc_list[j].insert(reloc_list[j].begin(), fixup_list.begin(), fixup_list.end());
+
+ dir = file.command_list()->GetCommandByType(rel_dir_types[j]);
+ if (!dir)
+ dir = file.command_list()->Add(rel_dir_types[j]);
+ dir->set_value(fixup_list.size());
+ } else {
+ for (i = 0; i < _countof(rel_dir_types); i++) {
+ dir = file.command_list()->GetCommandByType(rel_dir_types[i]);
+ if (dir)
+ delete dir;
+ }
+ }
+
+ dir = file.command_list()->GetCommandByType(DT_JMPREL);
+ ELFSection *jmprel_section = dir ? file.section_list()->GetSectionByAddress(dir->address()) : NULL;
+ for (i = 0; i < file.section_list()->count(); i++) {
+ ELFSection *section = file.section_list()->item(i);
+ if (section->type() != SHT_REL && section->type() != SHT_RELA)
+ continue;
+
+ if (jmprel_section && section == jmprel_section)
+ j = 2;
+ else
+ j = (section->type() == SHT_RELA) ? 1 : 0;
+ section_list[j] = section;
+ }
+
+ for (i = 0; i < _countof(reloc_list); i++) {
+ ELFSection *section = section_list[i];
+ size_t size = 0;
+ uint64_t pos = (section && section->alignment() > 1) ? file.Resize(AlignValue(file.Tell(), section->alignment())) : file.Tell();
+ uint64_t address = file.AddressTell();
+ for (k = 0; k < reloc_list[i].size(); k++) {
+ reloc = reloc_list[i].at(k);
+ size += reloc->WriteToFile(file);
+ }
+ if (section) {
+ section->Rebase(address - section->address());
+ section->set_physical_offset(static_cast<uint32_t>(pos));
+ section->set_size(static_cast<uint32_t>(size));
+ }
+
+ for (k = 0; k < 2; k++) {
+ dir = file.command_list()->GetCommandByType(dir_types[i][k]);
+ if (dir) {
+ if (size)
+ dir->set_value(k == 0 ? address : size);
+ else
+ delete dir;
+ }
+ }
+ }
+}
+
+void ELFRelocationList::Pack()
+{
+ for (size_t i = count(); i > 0 ; i--) {
+ ELFRelocation *reloc = item(i - 1);
+ if (reloc->symbol() && reloc->symbol()->is_deleted())
+ delete reloc;
+ }
+}
+
+/**
+ * ELFRuntimeFunction
+ */
+
+ELFRuntimeFunction::ELFRuntimeFunction(ELFRuntimeFunctionList *owner, uint64_t address, uint64_t begin, uint64_t end, uint64_t unwind_address,
+ CommonInformationEntry *cie, const std::vector<uint8_t> &call_frame_instructions)
+ : BaseRuntimeFunction(owner), address_(address), begin_(begin), end_(end), unwind_address_(unwind_address), cie_(cie),
+ call_frame_instructions_(call_frame_instructions)
+{
+
+}
+
+ELFRuntimeFunction::ELFRuntimeFunction(ELFRuntimeFunctionList *owner, const ELFRuntimeFunction &src)
+ : BaseRuntimeFunction(owner)
+{
+ address_ = src.address_;
+ begin_ = src.begin_;
+ end_ = src.end_;
+ unwind_address_ = src.unwind_address_;
+ cie_ = src.cie_;
+ call_frame_instructions_ = src.call_frame_instructions_;
+}
+
+ELFRuntimeFunction *ELFRuntimeFunction::Clone(IRuntimeFunctionList *owner) const
+{
+ ELFRuntimeFunction *func = new ELFRuntimeFunction(reinterpret_cast<ELFRuntimeFunctionList *>(owner), *this);
+ return func;
+}
+
+void ELFRuntimeFunction::Parse(IArchitecture &file, IFunction &dest)
+{
+ if (!file.AddressSeek(address_) || dest.GetCommandByAddress(address_))
+ return;
+
+ uint64_t address = address_;
+ IntelFunction &func = reinterpret_cast<IntelFunction &>(dest);
+
+ size_t c = func.count();
+ IntelCommand *command;
+ uint64_t value;
+ size_t pos;
+ CommandLink *link;
+ FunctionInfo *info;
+ std::vector<ICommand *> unwind_opcodes;
+
+ command = func.Add(address);
+ command->set_comment(CommentInfo(ttComment, "FDE Length"));
+ uint32_t fde_length = static_cast<uint32_t>(command->ReadValueFromFile(file, osDWord));
+ address = command->next_address();
+
+ if (fde_length) {
+ EncodedData fde(command->next_address(), file.cpu_address_size());
+ fde.ReadFromFile(file, fde_length);
+ pos = 0;
+
+ command = func.Add(address);
+ command->set_comment(CommentInfo(ttComment, "CIE Pointer"));
+ value = command->ReadDataDWord(fde, &pos);
+ uint64_t cie_address = address - value;
+ address = command->next_address();
+
+ IntelCommand *cie_command = func.GetCommandByAddress(cie_address);
+ if (!cie_command) {
+ size_t fde_pos = pos;
+ uint64_t fde_address = address;
+
+ address = cie_address;
+ file.AddressSeek(address);
+
+ command = func.Add(address);
+ cie_command = command;
+ command->set_comment(CommentInfo(ttComment, "CIE Length"));
+ uint32_t cie_length = static_cast<uint32_t>(command->ReadValueFromFile(file, osDWord));
+ address = command->next_address();
+
+ if (cie_length) {
+ EncodedData cie(command->next_address(), file.cpu_address_size());
+ cie.ReadFromFile(file, cie_length);
+ pos = 0;
+
+ command = func.Add(address);
+ command->set_comment(CommentInfo(ttComment, "CIE ID"));
+ command->ReadDataDWord(cie, &pos);
+ address = command->next_address();
+
+ command = func.Add(address);
+ command->set_comment(CommentInfo(ttComment, "CIE Version"));
+ command->ReadDataByte(cie, &pos);
+ address = command->next_address();
+
+ command = func.Add(address);
+ command->ReadString(cie, &pos);
+ command->set_comment(CommentInfo(ttComment, string_format("Augmentation String: %s", cie_->augmentation().c_str())));
+ address = command->next_address();
+
+ command = func.Add(address);
+ command->ReadUleb128(cie, &pos);
+ command->set_comment(CommentInfo(ttComment, "Code Alignment Factor"));
+ address = command->next_address();
+
+ command = func.Add(address);
+ command->ReadSleb128(cie, &pos);
+ command->set_comment(CommentInfo(ttComment, "Data Alignment Factor"));
+ address = command->next_address();
+
+ command = func.Add(address);
+ command->ReadDataByte(cie, &pos);
+ command->set_comment(CommentInfo(ttComment, "Return Address Register"));
+ address = command->next_address();
+
+ if (*cie_->augmentation().c_str() == 'z') {
+ command = func.Add(address);
+ command->ReadUleb128(cie, &pos);
+ command->set_comment(CommentInfo(ttComment, "Augmentation Length"));
+ address = command->next_address();
+
+ for (size_t j = 1; j < cie_->augmentation().size(); j++) {
+ switch (cie_->augmentation().at(j)) {
+ case 'L':
+ command = func.Add(address);
+ command->set_comment(CommentInfo(ttComment, "LSDA Encoding"));
+ command->ReadDataByte(cie, &pos);
+ address = command->next_address();
+ break;
+ case 'R':
+ command = func.Add(address);
+ command->set_comment(CommentInfo(ttComment, "FDE Encoding"));
+ command->ReadDataByte(cie, &pos);
+ address = command->next_address();
+ break;
+ case 'P':
+ {
+ command = func.Add(address);
+ command->set_comment(CommentInfo(ttComment, "Personality Encoding"));
+ command->ReadDataByte(cie, &pos);
+ address = command->next_address();
+
+ command = func.Add(address);
+ command->ReadEncoding(cie, cie_->personality_encoding(), &pos);
+ command->set_comment(CommentInfo(ttComment, "Personality Routine"));
+ address = command->next_address();
+ }
+ break;
+ }
+ }
+ }
+
+ command = func.Add(address);
+ command->ReadData(cie, cie.size() - pos, &pos);
+ command->set_comment(CommentInfo(ttComment, "Initial Instructions"));
+ address = command->next_address();
+ }
+
+ file.AddressSeek(fde_address);
+ address = fde_address;
+ pos = fde_pos;
+ }
+
+ command = func.Add(address);
+ command->ReadEncoding(fde, cie_->fde_encoding(), &pos);
+ command->set_comment(CommentInfo(ttComment, string_format("Begin: %llX", begin())));
+ address = command->next_address();
+
+ command = func.Add(address);
+ command->ReadEncoding(fde, cie_->fde_encoding() & 0x0f, &pos);
+ command->set_comment(CommentInfo(ttComment, string_format("End: %llX", end())));
+ address = command->next_address();
+
+ if (*cie_->augmentation().c_str() == 'z') {
+ command = func.Add(address);
+ value = command->ReadUleb128(fde, &pos);
+ command->set_comment(CommentInfo(ttComment, "Augmentation Length"));
+ address = command->next_address();
+
+ if (cie_->augmentation().find('L') != std::string::npos) {
+ command = func.Add(address);
+ command->ReadEncoding(fde, cie_->lsda_encoding(), &pos);
+ command->set_comment(CommentInfo(ttComment, "LSDA"));
+ if (unwind_address_)
+ command->AddLink(0, ltOffset, unwind_address_);
+
+ address = command->next_address();
+ }
+ }
+
+ uint64_t pc = begin();
+ while (pos < fde.size()) {
+ command = func.Add(address);
+ size_t cur_pos = pos;
+ uint8_t b = fde.ReadByte(&pos);
+ switch (b) {
+ case DW_CFA_nop:
+ command->ReadData(fde, fde.size() - cur_pos, &cur_pos);
+ command->set_comment(CommentInfo(ttComment, "DW_CFA_nop"));
+ break;
+ case DW_CFA_set_loc:
+ pc = fde.ReadEncoding(cie_->fde_encoding(), &pos);
+ command->ReadData(fde, pos - cur_pos, &cur_pos);
+ command->set_comment(CommentInfo(ttComment, "DW_CFA_set_loc"));
+ break;
+ case DW_CFA_advance_loc1:
+ value = fde.ReadByte(&pos);
+ command->ReadData(fde, pos - cur_pos, &cur_pos);
+ command->set_comment(CommentInfo(ttComment, "DW_CFA_advance_loc1"));
+ func.range_list()->Add(pc, pc + value, NULL, NULL, command);
+ pc += value;
+ break;
+ case DW_CFA_advance_loc2:
+ value = fde.ReadWord(&pos);
+ command->ReadData(fde, pos - cur_pos, &cur_pos);
+ command->set_comment(CommentInfo(ttComment, "DW_CFA_advance_loc2"));
+ func.range_list()->Add(pc, pc + value, NULL, NULL, command);
+ pc += value;
+ break;
+ case DW_CFA_advance_loc4:
+ value = fde.ReadDWord(&pos);
+ command->ReadData(fde, pos - cur_pos, &cur_pos);
+ command->set_comment(CommentInfo(ttComment, "DW_CFA_advance_loc4"));
+ func.range_list()->Add(pc, pc + value, NULL, NULL, command);
+ pc += value;
+ break;
+ case DW_CFA_offset_extended:
+ fde.ReadUleb128(&pos);
+ fde.ReadUleb128(&pos);
+ command->ReadData(fde, pos - cur_pos, &cur_pos);
+ command->set_comment(CommentInfo(ttComment, "DW_CFA_offset_extended"));
+ break;
+ case DW_CFA_restore_extended:
+ fde.ReadUleb128(&pos);
+ command->ReadData(fde, pos - cur_pos, &cur_pos);
+ command->set_comment(CommentInfo(ttComment, "DW_CFA_restore_extended"));
+ break;
+ case DW_CFA_undefined:
+ fde.ReadUleb128(&pos);
+ command->ReadData(fde, pos - cur_pos, &cur_pos);
+ command->set_comment(CommentInfo(ttComment, "DW_CFA_undefined"));
+ break;
+ case DW_CFA_same_value:
+ fde.ReadUleb128(&pos);
+ command->ReadData(fde, pos - cur_pos, &cur_pos);
+ command->set_comment(CommentInfo(ttComment, "DW_CFA_same_value"));
+ break;
+ case DW_CFA_register:
+ fde.ReadUleb128(&pos);
+ fde.ReadUleb128(&pos);
+ command->ReadData(fde, pos - cur_pos, &cur_pos);
+ command->set_comment(CommentInfo(ttComment, "DW_CFA_register"));
+ break;
+ case DW_CFA_remember_state:
+ command->ReadData(fde, pos - cur_pos, &cur_pos);
+ command->set_comment(CommentInfo(ttComment, "DW_CFA_remember_state"));
+ break;
+ case DW_CFA_restore_state:
+ command->ReadData(fde, pos - cur_pos, &cur_pos);
+ command->set_comment(CommentInfo(ttComment, "DW_CFA_restore_state"));
+ break;
+ case DW_CFA_def_cfa:
+ fde.ReadUleb128(&pos);
+ fde.ReadUleb128(&pos);
+ command->ReadData(fde, pos - cur_pos, &cur_pos);
+ command->set_comment(CommentInfo(ttComment, "DW_CFA_def_cfa"));
+ break;
+ case DW_CFA_def_cfa_register:
+ fde.ReadUleb128(&pos);
+ command->ReadData(fde, pos - cur_pos, &cur_pos);
+ command->set_comment(CommentInfo(ttComment, "DW_CFA_def_cfa_register"));
+ break;
+ case DW_CFA_def_cfa_offset:
+ fde.ReadUleb128(&pos);
+ command->ReadData(fde, pos - cur_pos, &cur_pos);
+ command->set_comment(CommentInfo(ttComment, "DW_CFA_def_cfa_offset"));
+ break;
+ case DW_CFA_def_cfa_expression:
+ value = fde.ReadUleb128(&pos);
+ command->ReadData(fde, pos - cur_pos, &cur_pos);
+ command->set_comment(CommentInfo(ttComment, "DW_CFA_def_cfa_expression"));
+ pos += static_cast<size_t>(value);
+ break;
+ case DW_CFA_expression:
+ fde.ReadUleb128(&pos);
+ value = fde.ReadUleb128(&pos);
+ command->ReadData(fde, pos - cur_pos, &cur_pos);
+ command->set_comment(CommentInfo(ttComment, "DW_CFA_def_cfa_expression"));
+ pos += static_cast<size_t>(value);
+ break;
+ case DW_CFA_offset_extended_sf:
+ fde.ReadUleb128(&pos);
+ fde.ReadSleb128(&pos);
+ command->ReadData(fde, pos - cur_pos, &cur_pos);
+ command->set_comment(CommentInfo(ttComment, "DW_CFA_offset_extended_sf"));
+ break;
+ case DW_CFA_def_cfa_sf:
+ fde.ReadUleb128(&pos);
+ fde.ReadSleb128(&pos);
+ command->ReadData(fde, pos - cur_pos, &cur_pos);
+ command->set_comment(CommentInfo(ttComment, "DW_CFA_def_cfa_sf"));
+ break;
+ case DW_CFA_def_cfa_offset_sf:
+ fde.ReadSleb128(&pos);
+ command->ReadData(fde, pos - cur_pos, &cur_pos);
+ command->set_comment(CommentInfo(ttComment, "DW_CFA_def_cfa_offset_sf"));
+ break;
+ case DW_CFA_val_offset:
+ fde.ReadUleb128(&pos);
+ fde.ReadUleb128(&pos);
+ command->ReadData(fde, pos - cur_pos, &cur_pos);
+ command->set_comment(CommentInfo(ttComment, "DW_CFA_val_offset"));
+ break;
+ case DW_CFA_val_offset_sf:
+ fde.ReadUleb128(&pos);
+ fde.ReadSleb128(&pos);
+ command->ReadData(fde, pos - cur_pos, &cur_pos);
+ command->set_comment(CommentInfo(ttComment, "DW_CFA_val_offset_sf"));
+ break;
+ case DW_CFA_val_expression:
+ fde.ReadUleb128(&pos);
+ value = fde.ReadUleb128(&pos);
+ command->ReadData(fde, pos - cur_pos, &cur_pos);
+ command->set_comment(CommentInfo(ttComment, "DW_CFA_val_expression"));
+ pos += static_cast<size_t>(value);
+ break;
+ case DW_CFA_GNU_window_save:
+ command->ReadData(fde, pos - cur_pos, &cur_pos);
+ command->set_comment(CommentInfo(ttComment, "DW_CFA_GNU_window_save"));
+ break;
+ case DW_CFA_GNU_args_size:
+ fde.ReadUleb128(&pos);
+ command->ReadData(fde, pos - cur_pos, &cur_pos);
+ command->set_comment(CommentInfo(ttComment, "DW_CFA_GNU_args_size"));
+ break;
+ case DW_CFA_GNU_negative_offset_extended:
+ fde.ReadUleb128(&pos);
+ fde.ReadUleb128(&pos);
+ command->ReadData(fde, pos - cur_pos, &cur_pos);
+ command->set_comment(CommentInfo(ttComment, "DW_CFA_GNU_negative_offset_extended"));
+ break;
+ default:
+ switch (b & 0xc0) {
+ case DW_CFA_advance_loc:
+ value = (b & 0x3f);
+ command->ReadData(fde, pos - cur_pos, &cur_pos);
+ command->set_comment(CommentInfo(ttComment, "DW_CFA_advance_loc"));
+ func.range_list()->Add(pc, pc + value, NULL, NULL, command);
+ pc += value;
+ break;
+ case DW_CFA_offset:
+ fde.ReadUleb128(&pos);
+ command->ReadData(fde, pos - cur_pos, &cur_pos);
+ command->set_comment(CommentInfo(ttComment, "DW_CFA_offset"));
+ break;
+ case DW_CFA_restore:
+ command->ReadData(fde, pos - cur_pos, &cur_pos);
+ command->set_comment(CommentInfo(ttComment, "DW_CFA_restore"));
+ break;
+ default:
+ command->ReadData(fde, fde.size() - cur_pos, &cur_pos);
+ break;
+ }
+ }
+ pos = cur_pos;
+ address = command->next_address();
+
+ if (b != DW_CFA_nop)
+ unwind_opcodes.push_back(command);
+ }
+ }
+ for (size_t i = c; i < func.count(); i++) {
+ command = func.item(i);
+ command->exclude_option(roClearOriginalCode);
+ command->exclude_option(roNeedCompile);
+ }
+
+ if (unwind_address_ && file.AddressSeek(unwind_address_)) {
+ address = unwind_address_;
+
+ EncodedData lsda(address, file.cpu_address_size());
+ lsda.ReadFromFile(file, static_cast<size_t>(file.selected_segment()->address() + file.selected_segment()->physical_size() - address));
+ pos = 0;
+
+ command = func.Add(address);
+ command->set_comment(CommentInfo(ttComment, "LPStart Encoding"));
+ uint8_t start_encoding = command->ReadDataByte(lsda, &pos);
+ command->include_option(roCreateNewBlock);
+ address = command->next_address();
+
+ IntelCommand *entry = command;
+
+ uint64_t start = begin();
+ AddressBaseType base_type = btFunctionBegin;
+ if (start_encoding != DW_EH_PE_omit) {
+ command = func.Add(address);
+ command->set_comment(CommentInfo(ttComment, "LPStart"));
+ start = command->ReadEncoding(lsda, start_encoding, &pos);
+ address = command->next_address();
+ base_type = btValue;
+ }
+
+ info = func.function_info_list()->Add(begin(), end(), base_type, (base_type == btValue) ? start : 0, 0, 0xff, this, entry);
+ info->set_unwind_opcodes(unwind_opcodes);
+
+ command = func.Add(address);
+ command->set_comment(CommentInfo(ttComment, "TTable Encoding"));
+ uint8_t ttable_encoding = command->ReadDataByte(lsda, &pos);
+ address = command->next_address();
+
+ size_t ttable_offset = 0;
+ IntelCommand *ttable_offset_entry = NULL;
+ if (ttable_encoding != DW_EH_PE_omit) {
+ ttable_offset_entry = func.Add(address);
+ ttable_offset_entry->set_comment(CommentInfo(ttComment, "TTable Offset"));
+ ttable_offset_entry->include_option(roFillNop);
+ ttable_offset = static_cast<size_t>(ttable_offset_entry->ReadUleb128(lsda, &pos)) + pos;
+ address = ttable_offset_entry->next_address();
+ }
+
+ command = func.Add(address);
+ command->set_comment(CommentInfo(ttComment, "Call Site Encoding"));
+ uint8_t call_site_encoding = command->ReadDataByte(lsda, &pos);
+ address = command->next_address();
+
+ command = func.Add(address);
+ command->set_comment(CommentInfo(ttComment, "Call Site Length"));
+ uint64_t call_site_length = command->ReadUleb128(lsda, &pos);
+ address = command->next_address();
+
+ std::set<int64_t> action_list;
+ size_t old_pos = pos;
+ while (pos - old_pos < call_site_length) {
+ IntelCommand *begin_entry = func.Add(address);
+ uint64_t begin_address = start + begin_entry->ReadEncoding(lsda, call_site_encoding, &pos);
+ begin_entry->set_comment(CommentInfo(ttComment, string_format("Begin: %llX", begin_address)));
+ address = begin_entry->next_address();
+
+ IntelCommand *size_entry = func.Add(address);
+ uint64_t end_address = begin_address + size_entry->ReadEncoding(lsda, call_site_encoding, &pos);
+ size_entry->set_comment(CommentInfo(ttComment, string_format("End: %llX", end_address)));
+ address = size_entry->next_address();
+
+ func.range_list()->Add(begin_address, end_address, begin_entry, NULL, size_entry);
+
+ command = func.Add(address);
+ value = command->ReadEncoding(lsda, call_site_encoding, &pos);
+ if (value) {
+ value += begin();
+ link = command->AddLink(0, ltMemSEHBlock, value);
+ link->set_sub_value(begin());
+ link->set_base_function_info(info);
+ }
+ command->set_comment(CommentInfo(ttComment, string_format("Landing Pad: %llX", value)));
+ address = command->next_address();
+
+ command = func.Add(address);
+ command->set_comment(CommentInfo(ttComment, "Action"));
+ value = command->ReadUleb128(lsda, &pos);
+ address = command->next_address();
+
+ if (value)
+ action_list.insert(value);
+ }
+
+ if (ttable_encoding != DW_EH_PE_omit) {
+ std::set<int64_t> type_index_list;
+ std::set<int64_t> spec_index_list;
+ int64_t action = 1;
+ while (action_list.size()) {
+ action_list.erase(action);
+
+ old_pos = pos;
+
+ command = func.Add(address);
+ command->set_comment(CommentInfo(ttComment, "Type Filter"));
+ int64_t index = command->ReadSleb128(lsda, &pos);
+ address = command->next_address();
+
+ if (index > 0)
+ type_index_list.insert(index);
+ else if (index < 0)
+ spec_index_list.insert(index);
+
+ command = func.Add(address);
+ command->set_comment(CommentInfo(ttComment, "Next Action"));
+ int64_t next_action = command->ReadSleb128(lsda, &pos);
+ address = command->next_address();
+
+ action += pos - old_pos;
+
+ if (next_action >= action)
+ action_list.insert(next_action);
+ }
+
+ size_t old_count = func.count();
+
+ pos = ttable_offset;
+ address = lsda.address() + pos;
+ for (size_t i = 0; i < spec_index_list.size(); i++) {
+ command = func.Add(address);
+ command->set_comment(CommentInfo(ttComment, "Exception Spec"));
+ value = command->ReadUleb128(lsda, &pos);
+ address = command->next_address();
+
+ if (value > 0)
+ type_index_list.insert(value);
+ }
+
+ pos = ttable_offset - type_index_list.size() * lsda.encoding_size(ttable_encoding);
+ address = lsda.address() + pos;
+ for (size_t i = 0; i < type_index_list.size(); i++) {
+ command = func.Add(address);
+ command->set_comment(CommentInfo(ttComment, "Type Info"));
+ value = command->ReadEncoding(lsda, ttable_encoding, &pos);
+ if (command->operand(0).value)
+ link = command->AddLink(0, (ttable_encoding & 0x70) == DW_EH_PE_pcrel ? ltDelta : ltOffset, value);
+ address = command->next_address();
+ }
+
+ if (old_count < func.count()) {
+ address = func.item(old_count)->address();
+ link = ttable_offset_entry->AddLink(0, ltDelta, address);
+ link->set_sub_value(ttable_offset_entry->dump_size() + address - lsda.address() - ttable_offset);
+ }
+ }
+ } else {
+ // no LSDA
+ info = func.function_info_list()->Add(begin(), end(), btFunctionBegin, 0, 0, 0xff, this, NULL);
+ info->set_unwind_opcodes(unwind_opcodes);
+ }
+
+ for (size_t i = c; i < func.count(); i++) {
+ command = func.item(i);
+ command->exclude_option(roClearOriginalCode);
+ }
+}
+
+void ELFRuntimeFunction::Rebase(uint64_t delta_base)
+{
+ address_ += delta_base;
+ begin_ += delta_base;
+ end_ += delta_base;
+ if (unwind_address_)
+ unwind_address_ += delta_base;
+}
+
+/**
+ * ELFRuntimeFunctionList
+ */
+
+ELFRuntimeFunctionList::ELFRuntimeFunctionList()
+ : BaseRuntimeFunctionList(), version_(0), eh_frame_encoding_(DW_EH_PE_omit), fde_count_encoding_(DW_EH_PE_omit), fde_table_encoding_(DW_EH_PE_omit)
+{
+ cie_list_ = new CommonInformationEntryList();
+}
+
+ELFRuntimeFunctionList::ELFRuntimeFunctionList(const ELFRuntimeFunctionList &src)
+ : BaseRuntimeFunctionList(src)
+{
+ cie_list_ = src.cie_list_->Clone();
+ version_ = src.version_;
+ eh_frame_encoding_ = src.eh_frame_encoding_;
+ fde_count_encoding_ = src.fde_count_encoding_;
+ fde_table_encoding_ = src.fde_table_encoding_;
+ for (size_t i = 0; i < count(); i++) {
+ ELFRuntimeFunction *func = item(i);
+ func->set_cie(cie_list_->item(src.cie_list_->IndexOf(func->cie())));
+ }
+}
+
+ELFRuntimeFunctionList::~ELFRuntimeFunctionList()
+{
+ delete cie_list_;
+}
+
+ELFRuntimeFunctionList *ELFRuntimeFunctionList::Clone() const
+{
+ ELFRuntimeFunctionList *list = new ELFRuntimeFunctionList(*this);
+ return list;
+}
+
+void ELFRuntimeFunctionList::clear()
+{
+ cie_list_->clear();
+ BaseRuntimeFunctionList::clear();
+}
+
+ELFRuntimeFunction *ELFRuntimeFunctionList::item(size_t index) const
+{
+ return reinterpret_cast<ELFRuntimeFunction *>(IRuntimeFunctionList::item(index));
+}
+
+ELFRuntimeFunction *ELFRuntimeFunctionList::Add(uint64_t address, uint64_t begin, uint64_t end, uint64_t unwind_address, IRuntimeFunction *source, const std::vector<uint8_t> &call_frame_instructions)
+{
+ if (!source)
+ throw std::runtime_error("Invalid runtime function");
+
+ ELFRuntimeFunction *src = reinterpret_cast<ELFRuntimeFunction *>(source);
+ return Add(address, begin, end, unwind_address, src->cie(), call_frame_instructions);
+}
+
+ELFRuntimeFunction *ELFRuntimeFunctionList::Add(uint64_t address, uint64_t begin, uint64_t end, uint64_t unwind_address, CommonInformationEntry *cie, const std::vector<uint8_t> &call_frame_instructions)
+{
+ ELFRuntimeFunction *func = new ELFRuntimeFunction(this, address, begin, end, unwind_address, cie, call_frame_instructions);
+ AddObject(func);
+ return func;
+}
+
+ELFRuntimeFunction *ELFRuntimeFunctionList::GetFunctionByAddress(uint64_t address) const
+{
+ return reinterpret_cast<ELFRuntimeFunction *>(BaseRuntimeFunctionList::GetFunctionByAddress(address));
+}
+
+void ELFRuntimeFunctionList::ReadFromFile(ELFArchitecture &file)
+{
+ uint64_t address;
+ uint32_t size;
+ size_t pos;
+
+ if (ELFSegment *hdr_segment = file.segment_list()->GetSectionByType(PT_GNU_EH_FRAME)) {
+ if (!file.AddressSeek(hdr_segment->address()))
+ throw std::runtime_error("Invalid format");
+
+ EncodedData hdr(hdr_segment->address(), file.cpu_address_size());
+ hdr.ReadFromFile(file, hdr_segment->physical_size());
+ pos = 0;
+ version_ = hdr.ReadByte(&pos);
+ if (version_ != 1)
+ throw std::runtime_error("Invalid format");
+
+ eh_frame_encoding_ = hdr.ReadByte(&pos);
+ fde_count_encoding_ = hdr.ReadByte(&pos);
+ fde_table_encoding_ = hdr.ReadByte(&pos);
+ if (eh_frame_encoding_ == DW_EH_PE_omit)
+ throw std::runtime_error("Invalid format");
+
+ address = hdr.ReadEncoding(eh_frame_encoding_, &pos);
+ if (hdr_segment->address() > address)
+ size = static_cast<uint32_t>(hdr_segment->address() - address);
+ else {
+ ELFSegment *segment = file.segment_list()->GetSectionByAddress(address);
+ size = segment ? static_cast<uint32_t>(segment->address() + segment->physical_size() - address) : UINT32_MAX;
+ }
+ }
+ else {
+ ELFSection *eh_frame = file.section_list()->GetSectionByName(".eh_frame");
+ if (!eh_frame)
+ return;
+
+ address = eh_frame->address();
+ size = static_cast<uint32_t>(eh_frame->size());
+ }
+
+ if (!file.AddressSeek(address))
+ throw std::runtime_error("Invalid format");
+
+ std::map<uint64_t, CommonInformationEntry*> cie_map;
+ for (uint32_t i = 0; i < size; ) {
+ uint32_t length = file.ReadDWord();
+ if (!length)
+ break;
+
+ uint64_t cur_address = address + i;
+ EncodedData data(cur_address + sizeof(length), file.cpu_address_size());
+ data.ReadFromFile(file, length);
+ pos = 0;
+
+ uint32_t cie_id = data.ReadDWord(&pos);
+ if (cie_id == 0) {
+ // CIE
+ uint8_t fde_encoding = DW_EH_PE_absptr;
+ uint8_t lsda_encoding = DW_EH_PE_omit;
+ uint8_t personality_encoding = DW_EH_PE_omit;
+ uint64_t personality_routine = 0;
+
+ uint8_t version = data.ReadByte(&pos);
+ std::string augmentation = data.ReadString(&pos);
+ uint64_t code_alignment_factor = data.ReadUleb128(&pos);
+ uint64_t data_alignment_factor = data.ReadSleb128(&pos);
+ uint8_t return_address_register = data.ReadByte(&pos);
+ if (*augmentation.c_str() == 'z') {
+ data.ReadUleb128(&pos);
+ for (size_t j = 1; j < augmentation.size(); j++) {
+ switch (augmentation[j]) {
+ case 'L':
+ lsda_encoding = data.ReadByte(&pos);
+ break;
+ case 'R':
+ fde_encoding = data.ReadByte(&pos);
+ break;
+ case 'P':
+ {
+ personality_encoding = data.ReadByte(&pos);
+ personality_routine = data.ReadEncoding(personality_encoding, &pos);
+ }
+ break;
+ }
+ }
+ }
+
+ std::vector<uint8_t> initial_instructions;
+ initial_instructions.resize(length - pos);
+ if (!initial_instructions.empty())
+ data.Read(initial_instructions.data(), initial_instructions.size(), &pos);
+
+ CommonInformationEntry *cie = cie_list_->Add(version, augmentation, code_alignment_factor, data_alignment_factor, return_address_register, fde_encoding, lsda_encoding, personality_encoding, personality_routine, initial_instructions);
+ cie_map[cur_address] = cie;
+ } else {
+ // FDE
+ std::map<uint64_t, CommonInformationEntry*>::iterator it = cie_map.find(cur_address + sizeof(length) - cie_id);
+ if (it == cie_map.end())
+ throw std::runtime_error("Invalid CIE pointer");
+
+ CommonInformationEntry *cie = it->second;
+ uint64_t begin = data.ReadEncoding(cie->fde_encoding(), &pos);
+ uint64_t end = begin + data.ReadEncoding(cie->fde_encoding() & 0x0f, &pos);
+
+ uint64_t lsda_address = 0;
+ if (*cie->augmentation().c_str() == 'z') {
+ data.ReadUleb128(&pos);
+ if (cie->augmentation().find('L') != std::string::npos) {
+ size_t old_pos = pos;
+ if (data.ReadEncoding(cie->lsda_encoding() & 0x0f, &pos)) {
+ pos = old_pos;
+ lsda_address = data.ReadEncoding(cie->lsda_encoding(), &pos);
+ }
+ }
+ }
+ std::vector<uint8_t> call_frame_instructions;
+ call_frame_instructions.resize(length - pos);
+ if (!call_frame_instructions.empty())
+ data.Read(call_frame_instructions.data(), call_frame_instructions.size(), &pos);
+
+ Add(cur_address, begin, end, lsda_address, cie, call_frame_instructions);
+ }
+
+ i += sizeof(length) + length;
+ }
+}
+
+void ELFRuntimeFunctionList::WriteToFile(ELFArchitecture &file)
+{
+ Sort();
+
+ size_t i;
+ uint64_t pos, address;
+
+ ELFSegment *hdr_segment = file.segment_list()->GetSectionByType(PT_GNU_EH_FRAME);
+ ELFSection *eh_frame = file.section_list()->GetSectionByName(".eh_frame");
+ if (hdr_segment) {
+ pos = hdr_segment->alignment() > 1 ? file.Resize(AlignValue(file.Tell(), hdr_segment->alignment())) : file.Tell();
+ address = file.AddressTell();
+
+ EncodedData hdr(address, file.cpu_address_size());
+ // calc header size
+ size_t hdr_size = 4 * sizeof(uint8_t) + hdr.encoding_size(eh_frame_encoding_);
+ if (fde_count_encoding_ != DW_EH_PE_omit) {
+ hdr_size += hdr.encoding_size(fde_count_encoding_);
+ hdr_size += count() * 2 * hdr.encoding_size(fde_table_encoding_);
+ }
+ if (hdr_size < 8)
+ hdr_size = 8;
+
+ hdr_segment->Rebase(address - hdr_segment->address());
+ hdr_segment->set_physical_offset(static_cast<uint32_t>(pos));
+ hdr_segment->set_size(static_cast<uint32_t>(hdr_size));
+
+ if (ELFSection *section = file.section_list()->GetSectionByName(".eh_frame_hdr")) {
+ section->Rebase(address - section->address());
+ section->set_physical_offset(static_cast<uint32_t>(pos));
+ section->set_size(static_cast<uint32_t>(hdr_size));
+ }
+
+ pos = file.Resize(pos + hdr_size);
+ address += hdr_size;
+ } else {
+ if (!eh_frame)
+ return;
+
+ pos = eh_frame->alignment() > 1 ? file.Resize(AlignValue(file.Tell(), eh_frame->alignment())) : file.Tell();
+ address = file.AddressTell();
+ }
+
+ size_t res = 0;
+ std::map<CommonInformationEntry*, uint64_t> cie_map;
+ for (i = 0; i < count(); i++) {
+ ELFRuntimeFunction *func = item(i);
+ CommonInformationEntry *cie = func->cie();
+ std::map<CommonInformationEntry*, uint64_t>::iterator it = cie_map.find(cie);
+ uint64_t cie_address;
+ if (it == cie_map.end()) {
+ // write CIE
+ cie_address = address + res;
+
+ EncodedData data(cie_address + sizeof(uint32_t), file.cpu_address_size());
+ data.WriteDWord(0);
+ data.WriteByte(cie->version());
+ data.WriteString(cie->augmentation());
+ data.WriteUleb128(cie->code_alignment_factor());
+ data.WriteSleb128(cie->data_alignment_factor());
+ data.WriteByte(cie->return_address_register());
+ if (*cie->augmentation().c_str() == 'z') {
+ EncodedData tmp(data.address() + data.size() + 1, file.cpu_address_size());
+ for (size_t j = 1; j < cie->augmentation().size(); j++) {
+ switch (cie->augmentation().at(j)) {
+ case 'L':
+ tmp.WriteByte(cie->lsda_encoding());
+ break;
+ case 'R':
+ tmp.WriteByte(cie->fde_encoding());
+ break;
+ case 'P':
+ {
+ tmp.WriteByte(cie->personality_encoding());
+ tmp.WriteEncoding(cie->personality_encoding(), cie->personality_routine());
+ }
+ break;
+ }
+ }
+ data.WriteByte(static_cast<uint8_t>(tmp.size()));
+ data.Write(tmp.data(), tmp.size());
+ }
+ data.Write(cie->initial_instructions().data(), cie->initial_instructions().size());
+ data.resize(AlignValue(data.size(), sizeof(uint32_t)), 0);
+
+ uint32_t size = static_cast<uint32_t>(data.size());
+ res += file.Write(&size, sizeof(size));
+ res += file.Write(data.data(), data.size());
+ cie_map[cie] = cie_address;
+ } else {
+ cie_address = it->second;
+ }
+
+ // write FDE
+ func->set_address(address + res);
+ EncodedData data(address + res + sizeof(uint32_t), file.cpu_address_size());
+ data.WriteDWord(static_cast<uint32_t>(data.address() - cie_address));
+ data.WriteEncoding(cie->fde_encoding(), func->begin());
+ data.WriteEncoding(cie->fde_encoding() & 0x0f, func->end() - func->begin());
+ if (*cie->augmentation().c_str() == 'z') {
+ EncodedData tmp(data.address() + data.size() + 1, file.cpu_address_size());
+ if (cie->augmentation().find('L') != std::string::npos) {
+ if (func->unwind_address())
+ tmp.WriteEncoding(cie->lsda_encoding(), func->unwind_address());
+ else
+ tmp.WriteEncoding(cie->lsda_encoding() & 0x0f, 0);
+ }
+ data.WriteByte(static_cast<uint8_t>(tmp.size()));
+ data.Write(tmp.data(), tmp.size());
+ }
+ data.Write(func->call_frame_instructions().data(), func->call_frame_instructions().size());
+ data.resize(AlignValue(data.size(), sizeof(uint32_t)), 0);
+
+ uint32_t size = static_cast<uint32_t>(data.size());
+ res += file.Write(&size, sizeof(size));
+ res += file.Write(data.data(), data.size());
+ }
+ res += file.WriteDWord(0);
+
+ if (eh_frame) {
+ eh_frame->Rebase(address - eh_frame->address());
+ eh_frame->set_physical_offset(static_cast<uint32_t>(pos));
+ eh_frame->set_size(static_cast<uint32_t>(res));
+ }
+
+ if (hdr_segment) {
+ // write header
+ EncodedData hdr(hdr_segment->address(), file.cpu_address_size());
+ hdr.WriteByte(version_);
+ hdr.WriteByte(eh_frame_encoding_);
+ hdr.WriteByte(fde_count_encoding_);
+ hdr.WriteByte(fde_table_encoding_);
+ hdr.WriteEncoding(eh_frame_encoding_, address);
+ if (fde_count_encoding_ != DW_EH_PE_omit) {
+ hdr.WriteEncoding(fde_count_encoding_, count());
+ for (i = 0; i < count(); i++) {
+ ELFRuntimeFunction *func = item(i);
+ hdr.WriteEncoding(fde_table_encoding_, func->begin());
+ hdr.WriteEncoding(fde_table_encoding_, func->address());
+ }
+ }
+ if (hdr.size() < 8)
+ hdr.resize(8);
+
+ pos = file.Tell();
+ file.Seek(hdr_segment->physical_offset());
+ file.Write(hdr.data(), hdr.size());
+ file.Seek(pos);
+ }
+}
+
+void ELFRuntimeFunctionList::Rebase(uint64_t delta_base)
+{
+ cie_list_->Rebase(delta_base);
+ BaseRuntimeFunctionList::Rebase(delta_base);
+}
+
+/**
+ * ELFArchitecture
+ */
+
+ELFArchitecture::ELFArchitecture(ELFFile *owner, uint64_t offset, uint64_t size)
+ : BaseArchitecture(owner, offset, size), function_list_(NULL), virtual_machine_list_(NULL),
+ cpu_(0), file_type_(0), image_base_(0), cpu_address_size_(osDWord), entry_point_(0), segment_alignment_(0x1000), file_alignment_(0x10),
+ shstrndx_(0), shoff_(0), header_offset_(0), header_size_(0), resize_header_(0), header_segment_(NULL), overlay_offset_(0)
+{
+ dynsymbol_list_ = new ELFSymbolList(true);
+ symbol_list_ = new ELFSymbolList(false);
+ directory_list_ = new ELFDirectoryList(this);
+ segment_list_ = new ELFSegmentList(this);
+ import_list_ = new ELFImportList(this);
+ fixup_list_ = new ELFFixupList();
+ section_list_ = new ELFSectionList(this);
+ export_list_ = new ELFExportList(this);
+ relocation_list_ = new ELFRelocationList();
+ verneed_list_ = new ELFVerneedList();
+ verdef_list_ = new ELFVerdefList();
+ runtime_function_list_ = new ELFRuntimeFunctionList();
+}
+
+ELFArchitecture::ELFArchitecture(ELFFile *owner, const ELFArchitecture &src)
+ : BaseArchitecture(owner, src), function_list_(NULL), virtual_machine_list_(NULL), header_segment_(NULL)
+{
+ size_t i, j, k;
+
+ cpu_ = src.cpu_;
+ file_type_ = src.file_type_;
+ image_base_ = src.image_base_;
+ entry_point_ = src.entry_point_;
+ cpu_address_size_ = src.cpu_address_size_;
+ segment_alignment_ = src.segment_alignment_;
+ file_alignment_ = src.file_alignment_;
+ shstrndx_ = src.shstrndx_;
+ shoff_ = src.shoff_;
+ header_offset_ = src.header_offset_;
+ header_size_ = src.header_size_;
+ resize_header_ = src.resize_header_;
+ overlay_offset_ = src.overlay_offset_;
+
+ dynsymbol_list_ = src.dynsymbol_list_->Clone();
+ symbol_list_ = src.symbol_list_->Clone();
+ directory_list_ = src.directory_list_->Clone(this);
+ segment_list_ = src.segment_list_->Clone(this);
+ import_list_ = src.import_list_->Clone(this);
+ section_list_ = src.section_list_->Clone(this);
+ export_list_ = src.export_list_->Clone(this);
+ fixup_list_ = src.fixup_list_->Clone();
+ relocation_list_ = src.relocation_list_->Clone();
+ verneed_list_ = src.verneed_list_->Clone();
+ verdef_list_ = src.verdef_list_->Clone();
+ runtime_function_list_ = src.runtime_function_list_->Clone();
+
+ if (src.header_segment_)
+ header_segment_ = segment_list_->item(src.segment_list_->IndexOf(src.header_segment_));
+ if (src.function_list_)
+ function_list_ = src.function_list_->Clone(this);
+ if (src.virtual_machine_list_)
+ virtual_machine_list_ = src.virtual_machine_list_->Clone();
+
+ for (i = 0; i < src.relocation_list()->count(); i++) {
+ ELFRelocation *src_reloc = src.relocation_list()->item(i);
+ ELFSymbol *src_symbol = src_reloc->symbol();
+ if (!src_symbol)
+ continue;
+
+ relocation_list_->item(i)->set_symbol(dynsymbol_list_->item(src.dynsymbol_list()->IndexOf(src_symbol)));
+ }
+
+ for (i = 0; i < src.import_list()->count(); i++) {
+ ELFImport *src_import = src.import_list()->item(i);
+ for (j = 0; j < src_import->count(); j++) {
+ ELFImportFunction *import_function = import_list_->item(i)->item(j);
+ ELFImportFunction *src_import_function = src_import->item(j);
+ MapFunction *src_map_function = src_import_function->map_function();
+ if (src_map_function)
+ import_function->set_map_function(map_function_list()->item(src.map_function_list()->IndexOf(src_map_function)));
+
+ ELFSymbol *src_symbol = src_import_function->symbol();
+ if (!src_symbol)
+ continue;
+
+ import_function->set_symbol(dynsymbol_list_->item(src.dynsymbol_list()->IndexOf(src_symbol)));
+ }
+ }
+
+ for (i = 0; i < src.export_list()->count(); i++) {
+ ELFSymbol *symbol = src.export_list()->item(i)->symbol();
+ if (symbol)
+ export_list_->item(i)->set_symbol(dynsymbol_list_->item(src.dynsymbol_list_->IndexOf(symbol)));
+ }
+
+ if (function_list_) {
+ for (i = 0; i < function_list_->count(); i++) {
+ IntelFunction *func = reinterpret_cast<IntelFunction *>(function_list_->item(i));
+ for (j = 0; j < func->count(); j++) {
+ IntelCommand *command = func->item(j);
+
+ for (k = 0; k < 3; k++) {
+ IntelOperand operand = command->operand(k);
+ if (operand.type == otNone)
+ break;
+
+ if (operand.fixup)
+ command->set_operand_fixup(k, fixup_list_->GetFixupByAddress(operand.fixup->address()));
+ if (operand.relocation)
+ command->set_operand_relocation(k, relocation_list_->GetRelocationByAddress(operand.relocation->address()));
+ }
+ }
+ for (j = 0; j < func->function_info_list()->count(); j++) {
+ FunctionInfo *info = func->function_info_list()->item(j);
+ if (info->source())
+ info->set_source(runtime_function_list_->GetFunctionByAddress(info->source()->begin()));
+ }
+ }
+ }
+}
+
+ELFArchitecture::~ELFArchitecture()
+{
+ delete export_list_;
+ delete dynsymbol_list_;
+ delete directory_list_;
+ delete segment_list_;
+ delete import_list_;
+ delete section_list_;
+ delete fixup_list_;
+ delete relocation_list_;
+ delete symbol_list_;
+ delete verneed_list_;
+ delete verdef_list_;
+ delete function_list_;
+ delete virtual_machine_list_;
+ delete runtime_function_list_;
+}
+
+ELFArchitecture *ELFArchitecture::Clone(ELFFile *file) const
+{
+ ELFArchitecture *arch = new ELFArchitecture(file, *this);
+ return arch;
+}
+
+IArchitecture * ELFArchitecture::Clone(IFile *file) const
+{
+ return Clone(dynamic_cast<ELFFile *>(file));
+}
+
+OpenStatus ELFArchitecture::ReadFromFile(uint32_t mode)
+{
+ uint8_t ident[EI_NIDENT];
+
+ Seek(0);
+
+ if (size() < sizeof(ident))
+ return osUnknownFormat;
+
+ Read(&ident, sizeof(ident));
+ if (ident[EI_MAG0] != 0x7f || ident[EI_MAG1] != 'E' || ident[EI_MAG2] != 'L' || ident[EI_MAG3] != 'F')
+ return osUnknownFormat;
+
+ Seek(0);
+
+ uint16_t shnum, phnum;
+ size_t i;
+
+ switch (ident[EI_CLASS]){
+ case ELFCLASS32:
+ {
+ Elf32_Ehdr hdr;
+ Read(&hdr, sizeof(hdr));
+ if (hdr.e_version != EV_CURRENT)
+ return osInvalidFormat;
+ entry_point_ = hdr.e_entry;
+ cpu_ = hdr.e_machine;
+ file_type_ = hdr.e_type;
+ shoff_ = hdr.e_shoff;
+ shnum = hdr.e_shnum;
+ shstrndx_ = hdr.e_shstrndx;
+ header_offset_ = hdr.e_phoff;
+ phnum = hdr.e_phnum;
+ }
+ cpu_address_size_ = osDWord;
+ segment_alignment_ = 0x1000;
+ break;
+ case ELFCLASS64:
+ {
+ Elf64_Ehdr hdr;
+ Read(&hdr, sizeof(hdr));
+ if (hdr.e_version != EV_CURRENT)
+ return osInvalidFormat;
+ entry_point_ = hdr.e_entry;
+ cpu_ = hdr.e_machine;
+ file_type_ = hdr.e_type;
+ shoff_ = hdr.e_shoff;
+ shnum = hdr.e_shnum;
+ shstrndx_ = hdr.e_shstrndx;
+ if (hdr.e_phoff >> 32)
+ return osInvalidFormat;
+ header_offset_ = static_cast<uint32_t>(hdr.e_phoff);
+ phnum = hdr.e_phnum;
+ }
+ cpu_address_size_ = osQWord;
+ segment_alignment_ = 0x200000;
+ break;
+ default:
+ return osInvalidFormat;
+ };
+
+ file_alignment_ = 0x10;
+
+ switch (ident[EI_OSABI]) {
+ case ELFOSABI_NONE:
+ case ELFOSABI_GNU:
+ // supported type
+ break;
+ default:
+ return osUnsupportedSubsystem;
+ }
+
+ switch (file_type_) {
+ case ET_EXEC:
+ case ET_DYN:
+ // supported type
+ break;
+ default:
+ return osUnsupportedSubsystem;
+ }
+
+ switch (cpu_) {
+ case EM_386:
+ case EM_486:
+ case EM_X86_64:
+ // supported cpu
+ break;
+ default:
+ return osUnsupportedCPU;
+ }
+
+ Seek(header_offset_);
+ segment_list_->ReadFromFile(*this, phnum);
+ header_size_ = static_cast<uint32_t>(Tell());
+
+ image_base_ = 0;
+ for (i = 0; i < segment_list_->count(); i++) {
+ ELFSegment *segment = segment_list_->item(i);
+ if (segment->type() != PT_LOAD) {
+ segment->set_need_parse(false);
+ continue;
+ }
+
+ uint64_t segment_base = segment_list_->item(i)->address() & 0xffffffff00000000ull;
+ if (!image_base_) {
+ image_base_ = segment_base;
+ } else if (image_base_ != segment_base) {
+ return osInvalidFormat;
+ }
+ }
+
+ overlay_offset_ = shoff_ + shnum * (cpu_address_size() == osDWord ? sizeof(Elf32_Shdr) : sizeof(Elf64_Shdr));
+ if (overlay_offset_ == size())
+ overlay_offset_ = 0 ;
+
+ if (shnum) {
+ Seek(shoff_);
+ section_list_->ReadFromFile(*this, shnum);
+ }
+ directory_list_->ReadFromFile(*this);
+ dynsymbol_list_->string_table()->ReadFromFile(*this);
+ directory_list_->ReadStrings(*dynsymbol_list_->string_table());
+ dynsymbol_list_->ReadFromFile(*this);
+ relocation_list_->ReadFromFile(*this);
+ symbol_list_->ReadFromFile(*this);
+ verdef_list_->ReadFromFile(*this);
+ verneed_list_->ReadFromFile(*this);
+ export_list_->ReadFromFile(*this);
+ import_list_->ReadFromFile(*this);
+ runtime_function_list_->ReadFromFile(*this);
+
+ header_segment_ = NULL;
+ for (i = 0; i < segment_list_->count(); i++) {
+ ELFSegment *segment = segment_list_->item(i);
+ if (segment->type() != PT_LOAD)
+ continue;
+
+ if (segment->physical_size() && segment->physical_offset() == 0) {
+ header_segment_ = segment;
+ break;
+ }
+ }
+
+ if ((mode & foHeaderOnly) == 0) {
+ if (!owner()->file_name().empty()) {
+ MapFile map_file;
+ std::vector<uint64_t> segments;
+ for (size_t i = 0; i < segment_list()->count(); i++) {
+ segments.push_back(segment_list()->item(i)->address());
+ }
+ if (std::find(segments.begin(), segments.end(), 0) == segments.end())
+ segments.insert(segments.begin(), 0);
+ if (map_file.Parse(map_file_name().c_str(), segments))
+ ReadMapFile(map_file);
+ }
+
+ for (size_t k = 0; k < 2; k++) {
+ ELFSymbolList *symbol_list = (k == 0) ? dynsymbol_list_ : symbol_list_;
+ for (i = 0; i < symbol_list_->count(); i++) {
+ ELFSymbol *symbol = symbol_list_->item(i);
+ if (symbol->type() != STT_FUNC && symbol->type() != STT_OBJECT && !symbol->section_idx())
+ continue;
+
+ MapFunction *map_function = map_function_list()->GetFunctionByAddress(symbol->address());
+ if (!map_function)
+ map_function = map_function_list()->Add(symbol->address(), 0, otUnknown, DemangleName(symbol->name()));
+
+ ObjectType type = (symbol->type() == STT_FUNC && (segment_list_->GetMemoryTypeByAddress(symbol->address()) & mtExecutable)) ? otCode : otData;
+ map_function->set_type(type);
+ }
+ }
+
+ map_function_list()->ReadFromFile(*this);
+
+ switch (cpu_) {
+ case EM_386:
+ case EM_486:
+ case EM_X86_64:
+ function_list_ = new ELFIntelFunctionList(this);
+ virtual_machine_list_ = new IntelVirtualMachineList();
+ {
+ IntelFileHelper helper;
+ helper.Parse(*this);
+ }
+ break;
+ default:
+ return osUnsupportedCPU;
+ }
+ }
+
+ return osSuccess;
+}
+
+std::string ELFArchitecture::name() const
+{
+ switch (cpu_) {
+ case EM_M32:
+ case EM_SPARC32PLUS:
+ return std::string("sparc");
+ case EM_386:
+ return std::string("i386");
+ case EM_68K:
+ return std::string("m68K");
+ case EM_88K:
+ return std::string("m88K");
+ case EM_486:
+ return std::string("i486");
+ case EM_860:
+ return std::string("i860");
+ case EM_MIPS:
+ case EM_MIPS_RS3_LE:
+ return std::string("mips");
+ case EM_S370:
+ return std::string("s370");
+ case EM_PARISC:
+ return std::string("parisc");
+ case EM_VPP500:
+ return std::string("vpp500");
+ case EM_960:
+ return std::string("i960");
+ case EM_PPC:
+ return std::string("ppc");
+ case EM_PPC64:
+ return std::string("ppc64");
+ case EM_S390:
+ return std::string("s390");
+ case EM_SPU:
+ return std::string("spu");
+ case EM_V800:
+ return std::string("v800");
+ case EM_FR20:
+ return std::string("fr20");
+ case EM_RH32:
+ return std::string("rh32");
+ case EM_RCE:
+ return std::string("rce");
+ case EM_ARM:
+ return std::string("arm");
+ case EM_ALPHA:
+ return std::string("alpha");
+ case EM_SH:
+ return std::string("sh");
+ case EM_SPARCV9:
+ return std::string("sparc9");
+ case EM_TRICORE:
+ return std::string("tricore");
+ case EM_ARC:
+ return std::string("arc");
+ case EM_H8_300:
+ return std::string("h8/300");
+ case EM_H8_300H:
+ return std::string("h8/300h");
+ case EM_H8S:
+ return std::string("h8s");
+ case EM_H8_500:
+ return std::string("h8/500");
+ case EM_IA_64:
+ return std::string("ia64");
+ case EM_MIPS_X:
+ return std::string("mipsx");
+ case EM_COLDFIRE:
+ return std::string("coldfire");
+ case EM_68HC12:
+ return std::string("68hc12");
+ case EM_MMA:
+ return std::string("mma");
+ case EM_PCP:
+ return std::string("pcp");
+ case EM_NCPU:
+ return std::string("ncpu");
+ case EM_NDR1:
+ return std::string("ndr1");
+ case EM_STARCORE:
+ return std::string("starcore");
+ case EM_ME16:
+ return std::string("me16");
+ case EM_ST100:
+ return std::string("st100");
+ case EM_TINYJ:
+ return std::string("tinyj");
+ case EM_X86_64:
+ return std::string("amd64");
+ case EM_PDSP:
+ return std::string("pdsp");
+ case EM_PDP10:
+ return std::string("pdp10");
+ case EM_PDP11:
+ return std::string("pdp11");
+ case EM_FX66:
+ return std::string("fx66");
+ case EM_ST9PLUS:
+ return std::string("st9+");
+ case EM_ST7:
+ return std::string("st7");
+ /*
+
+ EM_ST7 = 68, // STMicroelectronics ST7 8-bit microcontroller
+ EM_68HC16 = 69, // Motorola MC68HC16 Microcontroller
+ EM_68HC11 = 70, // Motorola MC68HC11 Microcontroller
+ EM_68HC08 = 71, // Motorola MC68HC08 Microcontroller
+ EM_68HC05 = 72, // Motorola MC68HC05 Microcontroller
+ EM_SVX = 73, // Silicon Graphics SVx
+ EM_ST19 = 74, // STMicroelectronics ST19 8-bit microcontroller
+ EM_VAX = 75, // Digital VAX
+ EM_CRIS = 76, // Axis Communications 32-bit embedded processor
+ EM_JAVELIN = 77, // Infineon Technologies 32-bit embedded processor
+ EM_FIREPATH = 78, // Element 14 64-bit DSP Processor
+ EM_ZSP = 79, // LSI Logic 16-bit DSP Processor
+ EM_MMIX = 80, // Donald Knuth's educational 64-bit processor
+ EM_HUANY = 81, // Harvard University machine-independent object files
+ EM_PRISM = 82, // SiTera Prism
+ EM_AVR = 83, // Atmel AVR 8-bit microcontroller
+ EM_FR30 = 84, // Fujitsu FR30
+ EM_D10V = 85, // Mitsubishi D10V
+ EM_D30V = 86, // Mitsubishi D30V
+ EM_V850 = 87, // NEC v850
+ EM_M32R = 88, // Mitsubishi M32R
+ EM_MN10300 = 89, // Matsushita MN10300
+ EM_MN10200 = 90, // Matsushita MN10200
+ EM_PJ = 91, // picoJava
+ EM_OPENRISC = 92, // OpenRISC 32-bit embedded processor
+ EM_ARC_COMPACT = 93, // ARC International ARCompact processor (old
+ // spelling/synonym: EM_ARC_A5)
+ EM_XTENSA = 94, // Tensilica Xtensa Architecture
+ EM_VIDEOCORE = 95, // Alphamosaic VideoCore processor
+ EM_TMM_GPP = 96, // Thompson Multimedia General Purpose Processor
+ EM_NS32K = 97, // National Semiconductor 32000 series
+ EM_TPC = 98, // Tenor Network TPC processor
+ EM_SNP1K = 99, // Trebia SNP 1000 processor
+ EM_ST200 = 100, // STMicroelectronics (www.st.com) ST200
+ EM_IP2K = 101, // Ubicom IP2xxx microcontroller family
+ EM_MAX = 102, // MAX Processor
+ EM_CR = 103, // National Semiconductor CompactRISC microprocessor
+ EM_F2MC16 = 104, // Fujitsu F2MC16
+ EM_MSP430 = 105, // Texas Instruments embedded microcontroller msp430
+ EM_BLACKFIN = 106, // Analog Devices Blackfin (DSP) processor
+ EM_SE_C33 = 107, // S1C33 Family of Seiko Epson processors
+ EM_SEP = 108, // Sharp embedded microprocessor
+ EM_ARCA = 109, // Arca RISC Microprocessor
+ EM_UNICORE = 110, // Microprocessor series from PKU-Unity Ltd. and MPRC
+ // of Peking University
+ EM_EXCESS = 111, // eXcess: 16/32/64-bit configurable embedded CPU
+ EM_DXP = 112, // Icera Semiconductor Inc. Deep Execution Processor
+ EM_ALTERA_NIOS2 = 113, // Altera Nios II soft-core processor
+ EM_CRX = 114, // National Semiconductor CompactRISC CRX
+ EM_XGATE = 115, // Motorola XGATE embedded processor
+ EM_C166 = 116, // Infineon C16x/XC16x processor
+ EM_M16C = 117, // Renesas M16C series microprocessors
+ EM_DSPIC30F = 118, // Microchip Technology dsPIC30F Digital Signal
+ // Controller
+ EM_CE = 119, // Freescale Communication Engine RISC core
+ EM_M32C = 120, // Renesas M32C series microprocessors
+ EM_TSK3000 = 131, // Altium TSK3000 core
+ EM_RS08 = 132, // Freescale RS08 embedded processor
+ EM_SHARC = 133, // Analog Devices SHARC family of 32-bit DSP
+ // processors
+ EM_ECOG2 = 134, // Cyan Technology eCOG2 microprocessor
+ EM_SCORE7 = 135, // Sunplus S+core7 RISC processor
+ EM_DSP24 = 136, // New Japan Radio (NJR) 24-bit DSP Processor
+ EM_VIDEOCORE3 = 137, // Broadcom VideoCore III processor
+ EM_LATTICEMICO32 = 138, // RISC processor for Lattice FPGA architecture
+ EM_SE_C17 = 139, // Seiko Epson C17 family
+ EM_TI_C6000 = 140, // The Texas Instruments TMS320C6000 DSP family
+ EM_TI_C2000 = 141, // The Texas Instruments TMS320C2000 DSP family
+ EM_TI_C5500 = 142, // The Texas Instruments TMS320C55x DSP family
+ EM_MMDSP_PLUS = 160, // STMicroelectronics 64bit VLIW Data Signal Processor
+ EM_CYPRESS_M8C = 161, // Cypress M8C microprocessor
+ EM_R32C = 162, // Renesas R32C series microprocessors
+ EM_TRIMEDIA = 163, // NXP Semiconductors TriMedia architecture family
+ EM_HEXAGON = 164, // Qualcomm Hexagon processor
+ EM_8051 = 165, // Intel 8051 and variants
+ EM_STXP7X = 166, // STMicroelectronics STxP7x family of configurable
+ // and extensible RISC processors
+ EM_NDS32 = 167, // Andes Technology compact code size embedded RISC
+ // processor family
+ EM_ECOG1 = 168, // Cyan Technology eCOG1X family
+ EM_ECOG1X = 168, // Cyan Technology eCOG1X family
+ EM_MAXQ30 = 169, // Dallas Semiconductor MAXQ30 Core Micro-controllers
+ EM_XIMO16 = 170, // New Japan Radio (NJR) 16-bit DSP Processor
+ EM_MANIK = 171, // M2000 Reconfigurable RISC Microprocessor
+ EM_CRAYNV2 = 172, // Cray Inc. NV2 vector architecture
+ EM_RX = 173, // Renesas RX family
+ EM_METAG = 174, // Imagination Technologies META processor
+ // architecture
+ EM_MCST_ELBRUS = 175, // MCST Elbrus general purpose hardware architecture
+ EM_ECOG16 = 176, // Cyan Technology eCOG16 family
+ EM_CR16 = 177, // National Semiconductor CompactRISC CR16 16-bit
+ // microprocessor
+ EM_ETPU = 178, // Freescale Extended Time Processing Unit
+ EM_SLE9X = 179, // Infineon Technologies SLE9X core
+ EM_L10M = 180, // Intel L10M
+ EM_K10M = 181, // Intel K10M
+ EM_AARCH64 = 183, // ARM AArch64
+ EM_AVR32 = 185, // Atmel Corporation 32-bit microprocessor family
+ EM_STM8 = 186, // STMicroeletronics STM8 8-bit microcontroller
+ EM_TILE64 = 187, // Tilera TILE64 multicore architecture family
+ EM_TILEPRO = 188, // Tilera TILEPro multicore architecture family
+ EM_CUDA = 190, // NVIDIA CUDA architecture
+ EM_TILEGX = 191, // Tilera TILE-Gx multicore architecture family
+ EM_CLOUDSHIELD = 192, // CloudShield architecture family
+ EM_COREA_1ST = 193, // KIPO-KAIST Core-A 1st generation processor family
+ EM_COREA_2ND = 194, // KIPO-KAIST Core-A 2nd generation processor family
+ EM_ARC_COMPACT2 = 195, // Synopsys ARCompact V2
+ EM_OPEN8 = 196, // Open8 8-bit RISC soft processor core
+ EM_RL78 = 197, // Renesas RL78 family
+ EM_VIDEOCORE5 = 198, // Broadcom VideoCore V processor
+ EM_78KOR = 199, // Renesas 78KOR family
+ EM_56800EX = 200, // Freescale 56800EX Digital Signal Controller (DSC)
+ EM_BA1 = 201, // Beyond BA1 CPU architecture
+ EM_BA2 = 202, // Beyond BA2 CPU architecture
+ EM_XCORE = 203, // XMOS xCORE processor family
+ EM_MCHP_PIC = 204, // Microchip 8-bit PIC(r) family
+ EM_KM32 = 210, // KM211 KM32 32-bit processor
+ EM_KMX32 = 211, // KM211 KMX32 32-bit processor
+ EM_KMX16 = 212, // KM211 KMX16 16-bit processor
+ EM_KMX8 = 213, // KM211 KMX8 8-bit processor
+ EM_KVARC = 214, // KM211 KVARC processor
+ EM_CDP = 215, // Paneve CDP architecture family
+ EM_COGE = 216, // Cognitive Smart Memory Processor
+ EM_COOL = 217, // iCelero CoolEngine
+ EM_NORC = 218, // Nanoradio Optimized RISC
+ EM_CSR_KALIMBA = 219 // CSR Kalimba architecture family
+ */
+ default:
+ return string_format("unknown 0x%X", cpu_);
+ }
+}
+
+bool ELFArchitecture::Prepare(CompileContext &ctx)
+{
+ if ((ctx.options.flags & cpStripFixups) == 0 && file_type_ == ET_EXEC)
+ ctx.options.flags |= cpStripFixups;
+
+ if (ctx.options.flags & cpImportProtection)
+ ctx.options.flags &= ~cpImportProtection;
+
+ if (ctx.options.flags & cpResourceProtection)
+ ctx.options.flags &= ~cpResourceProtection;
+
+ if (!BaseArchitecture::Prepare(ctx))
+ return false;
+
+ ELFSegment *segment;
+ size_t i, j;
+
+ // calc new header size
+ uint32_t new_segment_count = static_cast<uint32_t>(segment_list_->count() + 2);
+ if (ctx.options.flags & cpStripDebugInfo) {
+ for (i = 0; i < segment_list_->count(); i++) {
+ segment = segment_list_->item(i);
+ if (segment->type() == PT_NOTE)
+ new_segment_count--;
+ }
+ }
+ if (ctx.runtime)
+ new_segment_count++;
+ if (section_list_->GetSectionByName("config"))
+ new_segment_count++;
+
+ // calc header resizes
+ uint32_t new_header_size = header_offset_ + new_segment_count * ((cpu_address_size() == osDWord) ? sizeof(Elf32_Phdr) : sizeof(Elf64_Phdr));
+ resize_header_ = new_header_size - header_size_;
+ for (i = 0; i < section_list_->count(); i++) {
+ ELFSection *section = section_list_->item(i);
+ if (section->physical_offset() > new_header_size)
+ continue;
+
+ switch (section->type()) {
+ case SHT_NULL:
+ case SHT_SYMTAB:
+ case SHT_STRTAB:
+ case SHT_RELA:
+ case SHT_REL:
+ case SHT_HASH:
+ case SHT_DYNAMIC:
+ case SHT_DYNSYM:
+ case SHT_GNU_HASH:
+ case SHT_GNU_versym:
+ case SHT_GNU_verdef:
+ case SHT_GNU_verneed:
+ // do nothing
+ break;
+ case SHT_NOTE:
+ if ((ctx.options.flags & cpStripDebugInfo) == 0)
+ new_header_size += static_cast<uint32_t>(section->size());
+ break;
+ case SHT_PROGBITS:
+ if (section->flags() & (SHF_WRITE | SHF_EXECINSTR)) {
+ Notify(mtError, NULL, language[lsCreateSegmentError]);
+ return false;
+ }
+ new_header_size += static_cast<uint32_t>(section->size());
+ break;
+ default:
+ Notify(mtError, NULL, language[lsCreateSegmentError]);
+ return false;
+ }
+ }
+
+ segment = segment_list_->last();
+ if (segment) {
+ uint64_t pos = AlignValue(segment->physical_offset() + segment->physical_size(), file_alignment_);
+ if (ctx.runtime) {
+ ELFArchitecture *runtime = reinterpret_cast<ELFArchitecture *>(ctx.runtime);
+ std::vector<std::string> static_lib_list;
+ if (export_list_->GetExportByName("__cxa_guard_acquire"))
+ static_lib_list.push_back("libstdc++.so");
+ if (!static_lib_list.empty()) {
+ for (i = 0; i < runtime->import_list()->count(); i++) {
+ ELFImport *import = runtime->import_list()->item(i);
+ for (j = 0; j < static_lib_list.size(); j++) {
+ std::string lib_name = static_lib_list[j];
+ if (import->name().substr(0, lib_name.size()) == lib_name) {
+ ELFVerneed *verneed = runtime->verneed_list()->GetVerneed(import->name());
+ if (verneed)
+ delete verneed;
+ import->set_name("");
+ break;
+ }
+ }
+ }
+ }
+
+ if (runtime->segment_list()->count()) {
+ if ((import_list()->GetRuntimeOptions() & roActivation) == 0) {
+ std::set<ELFSymbol *> remove_symbol_list;
+ std::vector<std::string> remove_lib_list;
+ remove_lib_list.push_back("libcurl.so");
+ for (i = runtime->import_list()->count(); i > 0 ; i--) {
+ ELFImport *import = runtime->import_list()->item(i - 1);
+ for (j = 0; j < remove_lib_list.size(); j++) {
+ std::string lib_name = remove_lib_list[j];
+ if (import->name().substr(0, lib_name.size()) == lib_name) {
+ for (size_t k = 0; k < import->count(); k++) {
+ ELFImportFunction *import_func = import->item(k);
+ remove_symbol_list.insert(import_func->symbol());
+ }
+ ELFVerneed *verneed = runtime->verneed_list()->GetVerneed(import->name());
+ if (verneed)
+ delete verneed;
+ delete import;
+ break;
+ }
+ }
+ }
+ if (!remove_symbol_list.empty()) {
+ for (i = runtime->relocation_list()->count(); i > 0; i--) {
+ ELFRelocation *relocation = runtime->relocation_list()->item(i - 1);
+ if (!relocation->symbol())
+ continue;
+
+ if (remove_symbol_list.find(relocation->symbol()) != remove_symbol_list.end())
+ delete relocation;
+ }
+ }
+ }
+
+ MemoryManager runtime_manager(runtime);
+ for (i = runtime->segment_list()->count(); i > 0; i--) {
+ ELFSegment *tmp = runtime->segment_list()->item(i - 1);
+ if (tmp->type() != PT_LOAD || i > 2)
+ delete tmp;
+ }
+ runtime->Rebase(AlignValue(segment->address() + segment->size(), segment_alignment()) + (pos & (segment_alignment() - 1)) - runtime->segment_list()->item(0)->address());
+ if (runtime->header_segment_)
+ runtime_manager.Add(runtime->header_segment_->address(), runtime->header_size_);
+ runtime_manager.Pack();
+ for (i = 0; i < runtime_manager.count(); i++) {
+ MemoryRegion *region = runtime_manager.item(i);
+ ctx.manager->Add(region->address(), region->size(), region->type());
+ }
+ segment = runtime->segment_list()->last();
+ } else {
+ runtime->Rebase(image_base() - runtime->image_base());
+ }
+ }
+
+ // add new segment
+ assert(segment);
+ ctx.manager->Add(AlignValue(segment->address() + segment->size(), segment_alignment()) + (pos & (segment_alignment() - 1)), UINT32_MAX, mtReadable | mtExecutable | mtWritable | (runtime_function_list()->count() ? mtSolid : mtNone));
+ }
+
+ for (i = 0; i < section_list_->count(); i++) {
+ ELFSection *section = section_list_->item(i);
+ if (!section->address())
+ continue;
+
+ switch (section->type()) {
+ case SHT_STRTAB:
+ case SHT_DYNSYM:
+ case SHT_SYMTAB:
+ if (section->physical_offset() > new_header_size)
+ ctx.manager->Add(section->address(), static_cast<size_t>(section->size()));
+ else if (section->physical_offset() < new_header_size && section->physical_offset() + section->size() > new_header_size) {
+ uint32_t delta = new_header_size - section->physical_offset();
+ ctx.manager->Add(section->address() + delta, static_cast<uint32_t>(section->size()) - delta);
+ }
+ break;
+ }
+ }
+
+ return true;
+}
+
+void ELFArchitecture::Rebase(uint64_t delta_base)
+{
+ BaseArchitecture::Rebase(delta_base);
+
+ fixup_list_->Rebase(*this, delta_base);
+ relocation_list_->Rebase(*this, delta_base);
+ dynsymbol_list_->Rebase(delta_base);
+ export_list_->Rebase(delta_base);
+ segment_list_->Rebase(delta_base);
+ section_list_->Rebase(delta_base);
+ import_list_->Rebase(delta_base);
+ function_list_->Rebase(delta_base);
+ directory_list_->Rebase(delta_base);
+ runtime_function_list_->Rebase(delta_base);
+
+ if (entry_point_)
+ entry_point_ += delta_base;
+ image_base_ += delta_base;
+}
+
+bool ELFArchitecture::WriteToFile()
+{
+ Seek(0);
+
+ uint16_t shnum = static_cast<uint16_t>(section_list_->count());
+ uint16_t phnum = static_cast<uint16_t>(segment_list_->count());
+ if (cpu_address_size_ == osDWord) {
+ Elf32_Ehdr hdr;
+ Read(&hdr, sizeof(hdr));
+ hdr.e_entry = static_cast<uint32_t>(entry_point_);
+ hdr.e_shoff = static_cast<uint32_t>(shoff_);
+ hdr.e_shnum = shnum;
+ hdr.e_shstrndx = shstrndx_;
+ hdr.e_phoff = static_cast<uint32_t>(header_offset_);
+ hdr.e_phnum = phnum;
+ Seek(0);
+ Write(&hdr, sizeof(hdr));
+ } else {
+ Elf64_Ehdr hdr;
+ Read(&hdr, sizeof(hdr));
+ hdr.e_entry = entry_point_;
+ hdr.e_shoff = shoff_;
+ hdr.e_shnum = shnum;
+ hdr.e_shstrndx = shstrndx_;
+ hdr.e_phoff = header_offset_;
+ hdr.e_phnum = phnum;
+ Seek(0);
+ Write(&hdr, sizeof(hdr));
+ }
+
+ ELFSegment *segment = segment_list_->GetSectionByType(PT_PHDR);
+ if (segment) {
+ uint32_t size = static_cast<uint32_t>(segment_list_->count() * ((cpu_address_size() == osDWord) ? sizeof(Elf32_Phdr) : sizeof(Elf64_Phdr)));
+ segment->set_size(size);
+ segment->set_physical_size(size);
+ }
+
+ Seek(header_offset_);
+ segment_list_->WriteToFile(*this);
+ header_size_ = static_cast<uint32_t>(Tell());
+
+ return true;
+}
+
+void ELFArchitecture::Save(CompileContext &ctx)
+{
+ size_t i, j, c;
+ uint8_t b;
+ MemoryManager *manager;
+ MemoryRegion *region;
+ ELFSegment *last_segment, *vmp_segment, *segment;
+ uint64_t address, pos, file_crc_address, file_crc_size_address, loader_crc_address, loader_crc_size_address,
+ loader_crc_hash_address;
+ uint32_t size, file_crc_size, loader_crc_size;
+ int vmp_index;
+ ELFSection *section;
+ std::vector<ELFSection *> stripped_section_list, copy_section_list;
+ const ELFArchitecture *src = dynamic_cast<const ELFArchitecture *>(source());
+
+ if (ctx.options.flags & cpStripDebugInfo) {
+ for (i = 0; i < section_list_->count(); i++) {
+ section = section_list_->item(i);
+ switch (section->type()) {
+ case SHT_PROGBITS:
+ if ((section->flags() & SHF_ALLOC) == 0) {
+ if (section->name().substr(0, 6) == ".debug" || section->name() == ".comment")
+ stripped_section_list.push_back(section);
+ }
+ break;
+ case SHT_NOTE:
+ stripped_section_list.push_back(section);
+ break;
+ }
+ }
+ for (i = segment_list_->count(); i > 0; i--) {
+ segment = segment_list_->item(i - 1);
+ if (segment->type() == PT_NOTE)
+ delete segment;
+ }
+ }
+
+ // resize header
+ if (resize_header_) {
+ Seek(header_offset_ + header_size_);
+ for (i = 0; i < resize_header_; i++) {
+ WriteByte(0);
+ }
+
+ uint32_t new_header_size = header_size_ + resize_header_;
+ for (i = 0; i < section_list_->count(); i++) {
+ ELFSection *section = section_list_->item(i);
+ if (section->physical_offset() > new_header_size || std::find(stripped_section_list.begin(), stripped_section_list.end(), section) != stripped_section_list.end())
+ continue;
+
+ switch (section->type()) {
+ case SHT_NOTE:
+ case SHT_PROGBITS:
+ src->Seek(section->physical_offset());
+ Seek(new_header_size);
+ size = static_cast<uint32_t>(section->size());
+ CopyFrom(*src, size);
+ for (j = 0; j < segment_list_->count(); j++) {
+ ELFSegment *segment = segment_list_->item(j);
+ if (segment->physical_offset() == section->physical_offset()) {
+ segment->Rebase(new_header_size - segment->physical_offset());
+ segment->set_physical_offset(new_header_size);
+ }
+ }
+ section->Rebase(new_header_size - section->physical_offset());
+ section->set_physical_offset(new_header_size);
+ new_header_size += size;
+ break;
+ }
+ }
+ }
+
+ // calc progress maximum
+ c = 0;
+ if (ctx.runtime)
+ c += ctx.runtime->segment_list()->count();
+ for (i = 0; i < function_list_->count(); i++) {
+ IFunction *func = function_list_->item(i);
+ for (j = 0; j < func->block_list()->count(); j++) {
+ CommandBlock *block = func->block_list()->item(j);
+ c += block->end_index() - block->start_index() + 1;
+ }
+ }
+ StartProgress(string_format("%s...", language[lsSaving].c_str()), c);
+
+ last_segment = segment_list_->last();
+ uint32_t old_image_size = last_segment->physical_offset() + last_segment->physical_size();
+
+ for (i = 0; i < section_list_->count(); i++) {
+ section = section_list_->item(i);
+ if (section->physical_offset() < old_image_size || section->type() == SHT_NOBITS || section->type() == SHT_SYMTAB || section->type() == SHT_STRTAB || std::find(stripped_section_list.begin(), stripped_section_list.end(), section) != stripped_section_list.end())
+ continue;
+
+ copy_section_list.push_back(section);
+ }
+
+ pos = Resize(AlignValue(old_image_size, file_alignment_));
+ address = AlignValue(last_segment->address() + last_segment->size(), segment_alignment_) + (pos & (segment_alignment_ - 1));
+ vmp_segment = segment_list_->Add(address, UINT32_MAX, static_cast<uint32_t>(pos), UINT32_MAX, PF_R, PT_LOAD, segment_alignment_);
+
+ // merge runtime objects
+ ELFArchitecture *runtime = reinterpret_cast<ELFArchitecture*>(ctx.runtime);
+ if (runtime && runtime->segment_list()->count()) {
+ // merge segments
+ for (i = 0; i < runtime->segment_list()->count(); i++) {
+ segment = runtime->segment_list()->item(i);
+ pos = Tell();
+ if (segment->physical_size()) {
+ runtime->Seek(segment->physical_offset());
+ size = static_cast<uint32_t>(segment->physical_size());
+ uint8_t *buffer = new uint8_t[size];
+ runtime->Read(buffer, size);
+ Write(buffer, size);
+ delete [] buffer;
+ }
+ size = (i == 0) ? static_cast<uint32_t>(runtime->segment_list()->item(i + 1)->address() - segment->address() - segment->physical_size()) : 0;
+ uint8_t b = 0;
+ for (j = 0; j < size; j++) {
+ Write(&b, sizeof(b));
+ }
+ vmp_segment->include_write_type(segment->memory_type() & (~mtWritable));
+
+ StepProgress();
+ }
+ // merge symbol versions
+ std::map<uint16_t, uint16_t> verneed_map;
+ uint16_t id = 1;
+ for (i = 0; i < verneed_list_->count(); i++) {
+ ELFVerneed *verneed = verneed_list_->item(i);
+ for (j = 0; j < verneed->count(); j++) {
+ ELFVernaux *vernaux = verneed->item(j);
+ if (id < vernaux->other())
+ id = vernaux->other();
+ }
+ }
+ for (i = runtime->verneed_list_->count(); i > 0; i--) {
+ ELFVerneed *src_verneed = runtime->verneed_list_->item(i - 1);
+ ELFVerneed *verneed = verneed_list_->GetVerneed(src_verneed->file());
+ if (!verneed) {
+ verneed = src_verneed->Clone(verneed_list_);
+ verneed_list_->InsertObject(0, verneed);
+ for (j = verneed->count(); j > 0; j--) {
+ verneed->item(j - 1)->set_other(++id);
+ }
+ }
+ for (j = src_verneed->count(); j > 0; j--) {
+ ELFVernaux *src_vernaux = src_verneed->item(j - 1);
+ ELFVernaux *vernaux = verneed->GetVernaux(src_vernaux->hash());
+ if (!vernaux) {
+ vernaux = src_vernaux->Clone(verneed);
+ verneed->InsertObject(0, vernaux);
+ vernaux->set_other(++id);
+ }
+ verneed_map[src_vernaux->other()] = vernaux->other();
+ }
+ }
+
+ // merge fixups
+ for (i = 0; i < runtime->fixup_list()->count(); i++) {
+ ELFFixup *fixup = runtime->fixup_list()->item(i);
+ fixup_list_->AddObject(fixup->Clone(fixup_list_));
+ }
+ // merge relocations
+ ELFDirectory *jmp_rel = directory_list_->GetCommandByType(DT_JMPREL);
+ std::map<ELFSymbol *, ELFSymbol *> symbol_map;
+ for (i = 0; i < runtime->relocation_list()->count(); i++) {
+ ELFRelocation *src_relocation = runtime->relocation_list()->item(i);
+ if (src_relocation->symbol()->bind() == STB_LOCAL) {
+ address = src_relocation->symbol()->address();
+ if (address && AddressSeek(src_relocation->address())) {
+ if (src_relocation->size() == osDWord)
+ WriteDWord(static_cast<uint32_t>(address));
+ else
+ WriteQWord(address);
+ fixup_list_->Add(src_relocation->address(), src_relocation->size());
+ }
+ } else {
+ ELFRelocation *relocation = src_relocation->Clone(relocation_list_);
+ if (jmp_rel == NULL && relocation->type() == R_386_JMP_SLOT)
+ relocation->set_type(R_386_GLOB_DAT);
+ relocation_list_->AddObject(relocation);
+
+ ELFSymbol *symbol;
+ std::map<ELFSymbol *, ELFSymbol *>::const_iterator it = symbol_map.find(src_relocation->symbol());
+ if (it == symbol_map.end()) {
+ symbol = src_relocation->symbol()->Clone(dynsymbol_list_);
+ dynsymbol_list_->AddObject(symbol);
+ if (symbol->version() > 1)
+ symbol->set_version(verneed_map[symbol->version()]);
+ symbol_map[src_relocation->symbol()] = symbol;
+ }
+ else {
+ symbol = it->second;
+ }
+ relocation->set_symbol(symbol);
+ }
+ }
+ // merge import
+ for (i = 0; i < runtime->import_list()->count(); i++) {
+ ELFImport *src_import = runtime->import_list()->item(i);
+ if (src_import->is_sdk())
+ continue;
+
+ ELFImport *import = import_list_->GetImportByName(src_import->name());
+ if (!import) {
+ import = new ELFImport(import_list_, src_import->name());
+ import_list_->AddObject(import);
+ }
+
+ for (j = 0; j < src_import->count(); j++) {
+ ELFImportFunction *src_import_function = src_import->item(j);
+ ELFImportFunction *import_function = src_import_function->Clone(import);
+ if (src_import_function->symbol()) {
+ std::map<ELFSymbol *, ELFSymbol *>::const_iterator it = symbol_map.find(src_import_function->symbol());
+ import_function->set_symbol(it->second);
+ }
+ import->AddObject(import_function);
+ }
+ }
+ // merge runtime functions
+ size_t old_count = runtime_function_list_->cie_list()->count();
+ for (i = 0; i < runtime->runtime_function_list()->cie_list()->count(); i++) {
+ CommonInformationEntry *cie = runtime->runtime_function_list()->cie_list()->item(i);
+ runtime_function_list_->cie_list()->AddObject(cie->Clone(runtime_function_list_->cie_list()));
+ }
+ for (i = 0; i < runtime->runtime_function_list()->count(); i++) {
+ ELFRuntimeFunction *runtime_function = runtime->runtime_function_list()->item(i)->Clone(runtime_function_list_);
+ runtime_function->set_cie(runtime_function_list()->cie_list()->item(old_count + runtime->runtime_function_list()->cie_list()->IndexOf(runtime_function->cie())));
+ runtime_function_list_->AddObject(runtime_function);
+ }
+ }
+
+ // write functions
+ for (i = 0; i < function_list_->count(); i++) {
+ function_list_->item(i)->WriteToFile(*this);
+ }
+
+ // erase not used memory regions
+ manager = memory_manager();
+ if (manager->count() > 1) {
+ // need skip last big region
+ for (i = 0; i < manager->count() - 1; i++) {
+ region = manager->item(i);
+ if (!AddressSeek(region->address()))
+ continue;
+
+ for (j = 0; j < region->size(); j++) {
+ b = (region->type() & mtReadable) ? rand() : 0xcc;
+ Write(&b, sizeof(b));
+ }
+ }
+ }
+
+ vmp_index = 0;
+ if (vmp_segment->write_type() == mtNone) {
+ delete vmp_segment;
+ } else {
+ size = static_cast<uint32_t>(this->size() - vmp_segment->physical_offset());
+ vmp_segment->set_size(size);
+ vmp_segment->set_physical_size(size);
+ vmp_segment->update_type(vmp_segment->write_type());
+
+ section_list_->Add(vmp_segment->address(), static_cast<uint32_t>(vmp_segment->size()), vmp_segment->physical_offset(), SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, string_format("%s%d", ctx.options.section_name.c_str(), vmp_index++));
+ }
+
+ if ((ctx.options.flags & cpPack) && ctx.options.script)
+ ctx.options.script->DoBeforePackFile();
+
+ // write memory CRC table
+ if (function_list_->crc_table()) {
+ IntelCRCTable *intel_crc = reinterpret_cast<IntelCRCTable *>(function_list_->crc_table());
+ CRCTable crc_table(function_list_->crc_cryptor(), intel_crc->table_size());
+
+ // add non writable segments
+ for (i = 0; i < segment_list_->count(); i++) {
+ segment = segment_list_->item(i);
+ if ((segment->memory_type() & (mtReadable | mtWritable)) != mtReadable || segment->excluded_from_memory_protection())
+ continue;
+
+ size = std::min(static_cast<uint32_t>(segment->size()), segment->physical_size());
+ if (size)
+ crc_table.Add(segment->address(), size);
+ }
+
+ // skip writable runtime's sections
+ if (runtime) {
+ for (i = 0; i < runtime->segment_list()->count(); i++) {
+ segment = runtime->segment_list()->item(i);
+ if (segment->memory_type() & mtWritable)
+ crc_table.Remove(segment->address(), static_cast<uint32_t>(segment->size()));
+ }
+ }
+
+ // skip header
+ if (header_segment_)
+ crc_table.Remove(header_segment_->address(), header_size_ + resize_header_);
+
+ // skip IAT
+ ELFDirectory *dir = directory_list_->GetCommandByType(DT_PLTGOT);
+ if (dir)
+ crc_table.Remove(dir->value(), OperandSizeToValue(cpu_address_size_) * 3);
+
+ // skip fixups
+ if ((ctx.options.flags & cpStripFixups) == 0) {
+ for (i = 0; i < fixup_list_->count(); i++) {
+ ELFFixup *fixup = fixup_list_->item(i);
+ if (!fixup->is_deleted())
+ crc_table.Remove(fixup->address(), OperandSizeToValue(fixup->size()));
+ }
+ }
+
+ // skip relocations
+ for (i = 0; i < relocation_list_->count(); i++) {
+ ELFRelocation *relocation = relocation_list_->item(i);
+ crc_table.Remove(relocation->address(), (relocation->type() == R_386_COPY) ? relocation->symbol()->size() : OperandSizeToValue(relocation->size()));
+ }
+
+ // skip loader_data
+ IntelFunction *loader_data = reinterpret_cast<IntelFunctionList *>(function_list_)->loader_data();
+ if (loader_data)
+ crc_table.Remove(loader_data->entry()->address(), loader_data->entry()->dump_size());
+
+ // skip memory CRC table
+ crc_table.Remove(intel_crc->table_entry()->address(), intel_crc->table_size());
+ crc_table.Remove(intel_crc->size_entry()->address(), sizeof(uint32_t));
+ crc_table.Remove(intel_crc->hash_entry()->address(), sizeof(uint32_t));
+
+ // write to file
+ AddressSeek(intel_crc->table_entry()->address());
+ uint32_t hash;
+ size = static_cast<uint32_t>(crc_table.WriteToFile(*this, false, &hash));
+ AddressSeek(intel_crc->size_entry()->address());
+ WriteDWord(size);
+ AddressSeek(intel_crc->hash_entry()->address());
+ WriteDWord(hash);
+
+ intel_crc->size_entry()->set_operand_value(0, size);
+ intel_crc->hash_entry()->set_operand_value(0, hash);
+ }
+ EndProgress();
+
+ import_list_->Pack();
+ if (!runtime) {
+ ELFSymbol *empty_symbol = NULL;
+ for (i = 0; i < relocation_list_->count(); i++) {
+ ELFRelocation *relocation = relocation_list_->item(i);
+ if (relocation->symbol()->is_deleted() && relocation->type() == R_386_JMP_SLOT) {
+ if (!empty_symbol) {
+ empty_symbol = new ELFSymbol(dynsymbol_list_);
+ dynsymbol_list_->AddObject(empty_symbol);
+ }
+ relocation->set_symbol(empty_symbol);
+ }
+ }
+ }
+ relocation_list_->Pack();
+ if (cpu_address_size() == osDWord) {
+ for (i = 0; i < function_list_->count(); i++) {
+ IntelFunction *func = reinterpret_cast<IntelFunction *>(function_list_->item(i));
+ for (j = 0; j < func->count(); j++) {
+ IntelCommand *command = func->item(j);
+ if (!command->block() || (command->block()->type() & mtExecutable) == 0)
+ continue;
+
+ for (size_t k = 0; k < 3; k++) {
+ IntelOperand operand = command->operand(k);
+ if (operand.type == otNone)
+ break;
+
+ ELFRelocation *reloc = reinterpret_cast<ELFRelocation *>(operand.relocation);
+ if (reloc && AddressSeek(reloc->address())) {
+ switch (reloc->size()) {
+ case osDWord:
+ WriteDWord(static_cast<uint32_t>(reloc->value()));
+ break;
+ case osQWord:
+ WriteQWord(reloc->value());
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (ctx.options.flags & cpStripDebugInfo)
+ symbol_list_->clear();
+ else {
+ std::set<std::string> name_list;
+ for (i = 0; i < dynsymbol_list_->count(); i++) {
+ ELFSymbol *symbol = dynsymbol_list_->item(i);
+ if (symbol->is_deleted())
+ name_list.insert(symbol->name());
+ }
+ for (i = 0; i < symbol_list_->count(); i++) {
+ ELFSymbol *symbol = symbol_list_->item(i);
+ if (name_list.find(symbol->name()) != name_list.end())
+ symbol->set_deleted(true);
+ }
+ }
+ dynsymbol_list_->Pack();
+ symbol_list_->Pack();
+
+ file_crc_address = 0;
+ file_crc_size = 0;
+ file_crc_size_address = 0;
+ loader_crc_address = 0;
+ loader_crc_size = 0;
+ loader_crc_size_address = 0;
+ loader_crc_hash_address = 0;
+ if (runtime) {
+ std::vector<IFunction *> processor_list = function_list_->processor_list();
+ IntelRuntimeCRCTable *runtime_crc_table = reinterpret_cast<IntelFunctionList *>(function_list_)->runtime_crc_table();
+ ELFIntelLoader *loader = new ELFIntelLoader(NULL, cpu_address_size());
+
+ last_segment = segment_list_->last();
+ pos = AlignValue((ctx.options.flags & cpPack) ? loader->GetPackedSize(this) : this->size(), file_alignment_);
+ address = AlignValue(last_segment->address() + last_segment->size(), segment_alignment_) + (pos & (segment_alignment_ - 1));
+
+ manager->clear();
+ manager->Add(address, UINT32_MAX, mtReadable | mtExecutable | mtWritable | (runtime_function_list()->count() ? mtSolid : mtNone));
+
+ if (!loader->Prepare(ctx)) {
+ delete loader;
+ throw std::runtime_error("Runtime error at Save");
+ }
+ size_t write_count = loader->count() + 10000;
+ size_t processor_count = 0;
+ for (i = 0; i < processor_list.size(); i++) {
+ processor_count += processor_list[i]->count();
+ }
+ ctx.file->StartProgress(string_format("%s...", language[lsSavingStartupCode].c_str()), loader->count() + write_count + processor_count);
+ loader->Compile(ctx);
+
+ segment = segment_list_->Add(address, UINT32_MAX, static_cast<uint32_t>(pos), UINT32_MAX, PF_R | PF_W | PF_X, PT_LOAD, segment_alignment_);
+ c = loader->WriteToFile(*this);
+ segment->update_type(segment->write_type());
+ for (i = 0; i < processor_list.size(); i++) {
+ processor_list[i]->WriteToFile(*this);
+ }
+ if (runtime_crc_table)
+ c += runtime_crc_table->WriteToFile(*this);
+
+ // correct progress position
+ write_count -= c;
+ if (write_count)
+ StepProgress(write_count);
+
+ size = static_cast<uint32_t>(this->size() - segment->physical_offset());
+ segment->set_size(size);
+ segment->set_physical_size(size);
+
+ section_list_->Add(segment->address(), static_cast<uint32_t>(segment->size()), segment->physical_offset(), SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, string_format("%s%d", ctx.options.section_name.c_str(), vmp_index++));
+
+ entry_point_ = loader->entry()->address();
+
+ if (loader->init_entry()) {
+ ELFDirectory *dir = directory_list_->GetCommandByType(DT_INIT);
+ if (!dir)
+ directory_list_->Add(DT_INIT);
+ dir->set_value(loader->init_entry()->address());
+ }
+
+ if (loader->import_entry()) {
+ address = loader->import_entry()->address();
+ ELFDirectory *dir = directory_list_->GetCommandByType(DT_PLTGOT);
+ if (dir) {
+ ELFSection *section = section_list_->GetSectionByAddress(dir->value());
+ if (section) {
+ section->Rebase(address - section->address());
+ section->set_physical_offset(static_cast<uint32_t>(segment->physical_offset() + address - segment->address()));
+ section->set_size(loader->import_size());
+ }
+ } else {
+ dir = directory_list_->Add(DT_PLTGOT);
+ }
+ dir->set_value(address);
+ }
+
+ if (loader->file_crc_entry()) {
+ file_crc_address = loader->file_crc_entry()->address();
+ file_crc_size = loader->file_crc_size();
+ file_crc_size_address = loader->file_crc_size_entry()->address();
+ }
+
+ if (loader->loader_crc_entry()) {
+ loader_crc_address = loader->loader_crc_entry()->address();
+ loader_crc_size = loader->loader_crc_size();
+ loader_crc_size_address = loader->loader_crc_size_entry()->address();
+ loader_crc_hash_address = loader->loader_crc_hash_entry()->address();
+ }
+
+ if (loader->preinit_entry()) {
+ ELFDirectory *dir = directory_list_->GetCommandByType(DT_PREINIT_ARRAY);
+ if (dir) {
+ ELFSection *section = section_list_->GetSectionByAddress(dir->value());
+ if (section) {
+ section->Rebase(address - section->address());
+ section->set_physical_offset(static_cast<uint32_t>(segment->physical_offset() + address - segment->address()));
+ section->set_size(loader->preinit_size());
+ }
+ } else
+ dir = directory_list_->Add(DT_PREINIT_ARRAY);
+ dir->set_value(loader->preinit_entry()->address());
+
+ dir = directory_list_->GetCommandByType(DT_PREINIT_ARRAYSZ);
+ if (!dir)
+ dir = directory_list_->Add(DT_PREINIT_ARRAYSZ);
+ dir->set_value(loader->preinit_size());
+ }
+
+ if (loader->term_entry()) {
+ address = loader->term_entry()->address();
+ ELFDirectory *dir = directory_list_->GetCommandByType(DT_FINI);
+ if (!dir)
+ dir = directory_list_->Add(DT_FINI);
+ dir->set_value(address);
+ }
+
+ if (loader->tls_entry()) {
+ address = loader->tls_entry()->address();
+ ELFSegment *tls_segment = segment_list_->GetSectionByType(PT_TLS);
+ if (tls_segment)
+ tls_segment->Rebase(address - tls_segment->address());
+ for (i = 0; i < section_list_->count(); i++) {
+ ELFSection *section = section_list_->item(i);
+ if ((section->flags() & SHF_TLS) == 0)
+ continue;
+
+ section->Rebase(address - section->address());
+ section->set_physical_offset(static_cast<uint32_t>(section->address() - segment->address() + segment->physical_offset()));
+ address += section->size();
+ }
+ }
+
+ delete loader;
+
+ ctx.file->EndProgress();
+
+ for (i = 0; i < relocation_list_->count(); i++) {
+ ELFRelocation *relocation = relocation_list_->item(i);
+ if (relocation->type() == R_386_GLOB_DAT) {
+ ELFDirectory *dir = directory_list_->GetCommandByType(relocation->is_rela() ? DT_RELA : DT_REL);
+ if (!dir) {
+ directory_list_->Add(relocation->is_rela() ? DT_RELA : DT_REL);
+ section = section_list_->Add(0, 0, 0, SHF_ALLOC, relocation->is_rela() ? SHT_RELA : SHT_REL, relocation->is_rela() ? ".rela.dyn" : ".rel.dyn");
+ section->set_link(static_cast<uint32_t>(section_list_->IndexOf(section_list_->GetSectionByType(SHT_DYNSYM))));
+ if (cpu_address_size_ == osDWord)
+ section->set_entry_size(relocation->is_rela() ? sizeof(Elf32_Rela) : sizeof(Elf32_Rel));
+ else
+ section->set_entry_size(relocation->is_rela() ? sizeof(Elf64_Rela) : sizeof(Elf64_Rel));
+
+ dir = directory_list_->GetCommandByType(relocation->is_rela() ? DT_RELASZ : DT_RELSZ);
+ if (!dir)
+ directory_list_->Add(relocation->is_rela() ? DT_RELASZ : DT_RELSZ);
+
+ dir = directory_list_->GetCommandByType(relocation->is_rela() ? DT_RELAENT : DT_RELENT);
+ if (!dir) {
+ dir = directory_list_->Add(relocation->is_rela() ? DT_RELAENT : DT_RELENT);
+ dir->set_value(section->entry_size());
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ // write ELF structures
+ last_segment = segment_list_->last();
+ pos = Resize(AlignValue(this->size(), file_alignment_));
+ address = AlignValue(last_segment->address() + last_segment->size(), segment_alignment_) + (pos & (segment_alignment_ - 1));
+ vmp_segment = segment_list_->Add(address, UINT32_MAX, static_cast<uint32_t>(pos), UINT32_MAX, PF_R | PF_W, PT_LOAD, segment_alignment_);
+
+ import_list_->WriteToFile(*this);
+ dynsymbol_list_->WriteToFile(*this);
+ verdef_list_->WriteToFile(*this);
+ verneed_list_->WriteToFile(*this);
+ if (ctx.options.flags & cpStripFixups)
+ fixup_list_->clear();
+ else
+ fixup_list_->Pack();
+ relocation_list_->WriteToFile(*this);
+ runtime_function_list_->WriteToFile(*this);
+
+ if (!directory_list_->GetCommandByType(DT_TEXTREL)) {
+ // check relocations for non-writable segments
+ for (i = 0; i < relocation_list_->count(); i++) {
+ ELFRelocation *relocation = relocation_list_->item(i);
+ uint32_t memory_type = segment_list_->GetMemoryTypeByAddress(relocation->address());
+ if (memory_type == mtNone)
+ continue;
+
+ if ((memory_type & mtWritable) == 0) {
+ directory_list_->Add(DT_TEXTREL);
+ break;
+ }
+ }
+ }
+ directory_list_->WriteToFile(*this);
+
+ size = static_cast<uint32_t>(this->size() - vmp_segment->physical_offset());
+ vmp_segment->set_size(size);
+ vmp_segment->set_physical_size(size);
+
+ // copy sections
+ for (i = 0; i < copy_section_list.size(); i++) {
+ section = copy_section_list[i];
+ pos = section->alignment() > 1 ? Resize(AlignValue(this->size(), section->alignment())) : this->size();
+ src->Seek(section->physical_offset());
+ CopyFrom(*src, section->size());
+ section->set_physical_offset(static_cast<uint32_t>(pos));
+ }
+ section = src->section_list_->GetSectionByName("config");
+ if (section) {
+ last_segment = segment_list_->last();
+ pos = Resize(AlignValue(this->size(), segment_alignment_));
+ address = AlignValue(last_segment->address() + last_segment->size(), segment_alignment_);
+ vmp_segment = segment_list_->Add(address, static_cast<uint32_t>(section->size()), static_cast<uint32_t>(pos), static_cast<uint32_t>(section->size()), PF_R | PF_W, PT_LOAD, segment_alignment_);
+ src->Seek(section->physical_offset());
+ CopyFrom(*src, section->size());
+ }
+
+ if (symbol_list_->count() == 0) {
+ section = section_list_->GetSectionByType(SHT_SYMTAB);
+ if (section) {
+ stripped_section_list.push_back(section_list_->item(section->link()));
+ stripped_section_list.push_back(section);
+ }
+ } else {
+ symbol_list_->WriteToFile(*this);
+ }
+
+ if (stripped_section_list.size()) {
+ std::vector<ELFSection *> orig_section_list;
+ std::map<size_t, size_t> index_map;
+ for (i = 0; i < section_list_->count(); i++) {
+ orig_section_list.push_back(section_list_->item(i));
+ }
+ for (i = stripped_section_list.size(); i > 0; i--) {
+ section = stripped_section_list[i - 1];
+ delete section;
+ }
+ for (i = 0; i < orig_section_list.size(); i++) {
+ section = orig_section_list[i];
+ index_map[i] = section_list_->IndexOf(section);
+ }
+ section_list_->RemapLinks(index_map);
+
+ std::map<size_t, size_t>::const_iterator it = index_map.find(shstrndx_);
+ if (it == index_map.end() || it->second == NOT_ID)
+ throw std::runtime_error("Invalid section index");
+ shstrndx_ = static_cast<uint16_t>(it->second);
+ }
+
+ if (section_list_->count())
+ shoff_ = section_list_->WriteToFile(*this);
+ else {
+ shoff_ = 0;
+ shstrndx_ = SHN_UNDEF;
+ }
+
+ // copy overlay
+ if (overlay_offset_) {
+ Seek(this->size());
+ src->Seek(overlay_offset_);
+ CopyFrom(*src, src->size() - overlay_offset_);
+ }
+
+ if (ctx.options.script)
+ ctx.options.script->DoAfterSaveFile();
+
+ // write header
+ WriteToFile();
+
+ // write header and loader CRC table
+ if (loader_crc_address) {
+ CRCTable crc_table(function_list_->crc_cryptor(), loader_crc_size);
+
+ // add header
+ if (header_segment_)
+ crc_table.Add(header_segment_->address(), header_size_);
+
+ // add loader segments
+ j = segment_list_->IndexOf(segment_list_->GetSectionByAddress(loader_crc_address));
+ if (j != NOT_ID) {
+ c = (ctx.options.flags & cpLoaderCRC) ? j + 1 : segment_list_->count();
+ for (i = j; i < c; i++) {
+ segment = segment_list_->item(i);
+ // first loader segment always has PROT_WRITE flag
+ if (i > j && (segment->memory_type() & mtWritable))
+ continue;
+
+ size = std::min(static_cast<uint32_t>(segment->size()), segment->physical_size());
+ if (size)
+ crc_table.Add(segment->address(), size);
+ }
+ }
+
+ // skip IAT
+ ELFDirectory *dir = directory_list_->GetCommandByType(DT_PLTGOT);
+ if (dir)
+ crc_table.Remove(dir->value(), OperandSizeToValue(cpu_address_size_) * 3);
+ // skip fixups
+ if ((ctx.options.flags & cpStripFixups) == 0) {
+ for (i = 0; i < fixup_list_->count(); i++) {
+ ELFFixup *fixup = fixup_list_->item(i);
+ if (!fixup->is_deleted())
+ crc_table.Remove(fixup->address(), OperandSizeToValue(fixup->size()));
+ }
+ }
+ // skip relocations
+ for (i = 0; i < relocation_list_->count(); i++) {
+ ELFRelocation *relocation = relocation_list_->item(i);
+ crc_table.Remove(relocation->address(), (relocation->type() == R_386_COPY) ? relocation->symbol()->size() : OperandSizeToValue(relocation->size()));
+ }
+ // skip loader CRC table
+ crc_table.Remove(loader_crc_address, loader_crc_size);
+ crc_table.Remove(loader_crc_size_address, sizeof(uint32_t));
+ crc_table.Remove(loader_crc_hash_address, sizeof(uint32_t));
+ // skip file CRC table
+ if (file_crc_address)
+ crc_table.Remove(file_crc_address, file_crc_size);
+ if (file_crc_size_address)
+ crc_table.Remove(file_crc_size_address, sizeof(uint32_t));
+
+ // write to file
+ AddressSeek(loader_crc_address);
+ uint32_t hash;
+ size = static_cast<uint32_t>(crc_table.WriteToFile(*this, false, &hash));
+ AddressSeek(loader_crc_size_address);
+ WriteDWord(size);
+ AddressSeek(loader_crc_hash_address);
+ WriteDWord(hash);
+ }
+
+ // write file CRC table
+ if (file_crc_address) {
+ CRCTable crc_table(function_list_->crc_cryptor(), file_crc_size - sizeof(uint32_t));
+
+ // add file range
+ crc_table.Add(1, static_cast<size_t>(this->size()) - 1);
+
+ // skip file CRC table
+ if (AddressSeek(file_crc_address))
+ crc_table.Remove(Tell(), file_crc_size);
+ if (AddressSeek(file_crc_size_address))
+ crc_table.Remove(Tell(), sizeof(uint32_t));
+ section = section_list_->GetSectionByType(0x80736967); // "signature"
+ if (section)
+ crc_table.Remove(section->physical_offset(), section->physical_size());
+
+ // write to file
+ AddressSeek(file_crc_address);
+ size = static_cast<uint32_t>(this->size());
+ Write(&size, sizeof(size));
+ size = static_cast<uint32_t>(crc_table.WriteToFile(*this, true));
+ AddressSeek(file_crc_size_address);
+ WriteDWord(size);
+ }
+
+ EndProgress();
+}
+
+bool ELFArchitecture::is_executable() const
+{
+ return file_type() == ET_EXEC;
+}
+
+/**
+ * ELFFile
+ */
+
+ELFFile::ELFFile(ILog *log)
+ : IFile(log), runtime_(NULL)
+{
+
+}
+
+ELFFile::~ELFFile()
+{
+ delete runtime_;
+}
+
+ELFFile::ELFFile(const ELFFile &src, const char *file_name)
+ : IFile(src, file_name), runtime_(NULL)
+{
+ for (size_t i = 0; i < src.count(); i++)
+ AddObject(src.item(i)->Clone(this));
+}
+
+std::string ELFFile::format_name() const
+{
+ return std::string("ELF");
+}
+
+ELFArchitecture *ELFFile::item(size_t index) const
+{
+ return reinterpret_cast<ELFArchitecture *>(IFile::item(index));
+}
+
+ELFArchitecture *ELFFile::Add(uint64_t offset, uint64_t size)
+{
+ ELFArchitecture *arch = new ELFArchitecture(this, offset, size);
+ AddObject(arch);
+ return arch;
+}
+
+OpenStatus ELFFile::ReadHeader(uint32_t open_mode)
+{
+ ELFArchitecture *arch = Add(0, size());
+ return arch->ReadFromFile(open_mode);
+}
+
+ELFFile *ELFFile::Clone(const char *file_name) const
+{
+ ELFFile *file = new ELFFile(*this, file_name);
+ return file;
+}
+
+bool ELFFile::Compile(CompileOptions &options)
+{
+ const ResourceInfo runtime_info[] = {
+ {lin_runtime32_so_file, sizeof(lin_runtime32_so_file), lin_runtime32_so_code},
+ {lin_runtime64_so_file, sizeof(lin_runtime64_so_file), lin_runtime64_so_code}
+ };
+
+ ELFArchitecture *arch = item(0);
+ ResourceInfo info = runtime_info[arch->cpu_address_size() == osDWord ? 0 : 1];
+ if (info.size > 1) {
+ runtime_ = new ELFFile(NULL);
+ if (!runtime_->OpenResource(info.file, info.size, true))
+ throw std::runtime_error("Runtime error at OpenResource");
+
+ Buffer buffer(info.code);
+ arch = runtime_->item(0);
+ arch->ReadFromBuffer(buffer);
+ for (size_t i = 0; i < arch->function_list()->count(); i++) {
+ arch->function_list()->item(i)->set_from_runtime(true);
+ }
+ for (size_t i = 0; i < arch->import_list()->count(); i++) {
+ ELFImport *import = arch->import_list()->item(i);
+ for (size_t j = 0; j < import->count(); j++) {
+ import->item(j)->include_option(ioFromRuntime);
+ }
+ }
+ }
+
+ return IFile::Compile(options);
+}
+
+bool ELFFile::is_executable() const
+{
+#ifdef __unix__
+ for (size_t i = 0; i < count(); i++) {
+ if (item(i)->is_executable())
+ return true;
+ }
+#endif
+ return false;
+}
+
+uint32_t ELFFile::disable_options() const
+{
+ uint32_t res = cpResourceProtection | cpImportProtection | cpVirtualFiles;
+ for (size_t i = 0; i < count(); i++) {
+ ELFArchitecture *arch = item(i);
+ if (arch->file_type() != ET_EXEC)
+ res |= cpStripFixups;
+ }
+ return res;
+} \ No newline at end of file