5514 lines
159 KiB
C++
5514 lines
159 KiB
C++
/**
|
|
* 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 §ion)
|
|
{
|
|
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;
|
|
} |