Merge pull request #388 from DrChat/elf_modules

(Experimental) ELF module support
This commit is contained in:
Ben Vanik
2015-08-16 07:55:28 -07:00
5 changed files with 302 additions and 34 deletions

144
src/xenia/cpu/elf_module.cc Normal file
View File

@@ -0,0 +1,144 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2015 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/cpu/elf_module.h"
#include <memory>
#include "xenia/base/byte_order.h"
#include "xenia/base/logging.h"
#include "xenia/cpu/processor.h"
namespace xe {
namespace cpu {
ElfModule::ElfModule(Processor* processor, kernel::KernelState* kernel_state)
: Module(processor), kernel_state_(kernel_state) {}
ElfModule::~ElfModule() {}
// ELF structures
struct elf32_ehdr {
uint8_t e_ident[16];
xe::be<uint16_t> e_type;
xe::be<uint16_t> e_machine;
xe::be<uint32_t> e_version;
xe::be<uint32_t> e_entry;
xe::be<uint32_t> e_phoff;
xe::be<uint32_t> e_shoff;
xe::be<uint32_t> e_flags;
xe::be<uint16_t> e_ehsize;
xe::be<uint16_t> e_phentsize;
xe::be<uint16_t> e_phnum;
xe::be<uint16_t> e_shentsize;
xe::be<uint16_t> e_shnum;
xe::be<uint16_t> e_shtrndx;
};
struct elf32_phdr {
xe::be<uint32_t> p_type;
xe::be<uint32_t> p_offset;
xe::be<uint32_t> p_vaddr;
xe::be<uint32_t> p_paddr;
xe::be<uint32_t> p_filesz;
xe::be<uint32_t> p_memsz;
xe::be<uint32_t> p_flags;
xe::be<uint32_t> p_align;
};
bool ElfModule::Load(const std::string& name, const std::string& path,
const void* elf_addr, size_t elf_length) {
name_ = name;
path_ = path;
uint8_t* pelf = (uint8_t*)elf_addr;
elf32_ehdr* hdr = (elf32_ehdr*)(pelf + 0x0);
if (hdr->e_ident[0] != 0x7F || hdr->e_ident[1] != 'E' ||
hdr->e_ident[2] != 'L' || hdr->e_ident[3] != 'F') {
// Not an ELF file!
return false;
}
assert_true(hdr->e_ident[4] == 1); // 32bit
if (hdr->e_type != 2 /* ET_EXEC */) {
// Not executable (shared objects not supported yet)
XELOGE("ELF: Could not load ELF because it isn't executable!");
return false;
}
if (hdr->e_machine != 20 /* EM_PPC */) {
// Not a PPC ELF!
XELOGE(
"ELF: Could not load ELF because target machine is not PPC! (target: "
"%d)",
hdr->e_machine);
return false;
}
// Parse LOAD program headers and load into memory.
if (!hdr->e_phoff) {
XELOGE("ELF: File doesn't have a program header!");
return false;
}
if (!hdr->e_entry) {
XELOGE("ELF: Executable has no entry point!");
return false;
}
// Entry point virtual address
entry_point_ = hdr->e_entry;
// Copy the ELF header
elf_header_mem_.resize(hdr->e_ehsize);
std::memcpy(elf_header_mem_.data(), hdr, hdr->e_ehsize);
assert_true(hdr->e_phentsize == sizeof(elf32_phdr));
elf32_phdr* phdr = (elf32_phdr*)(pelf + hdr->e_phoff);
for (uint32_t i = 0; i < hdr->e_phnum; i++) {
if (phdr[i].p_type == 1 /* PT_LOAD */) {
// Allocate and copy into memory.
// Base address @ 0x80000000
uint32_t virtual_addr = phdr[i].p_vaddr < 0x80000000
? phdr[i].p_vaddr + 0x80000000
: phdr[i].p_vaddr;
if (!memory()
->LookupHeap(virtual_addr)
->AllocFixed(
virtual_addr, phdr[i].p_memsz, phdr[i].p_align,
xe::kMemoryAllocationReserve | xe::kMemoryAllocationCommit,
xe::kMemoryProtectRead | xe::kMemoryProtectWrite)) {
XELOGE("ELF: Could not allocate memory!");
}
auto p = memory()->TranslateVirtual(virtual_addr);
std::memset(p, 0, phdr[i].p_memsz);
std::memcpy(p, pelf + phdr[i].p_offset,
std::min(phdr[i].p_memsz, phdr[i].p_filesz));
// Notify backend about executable code.
if (phdr[i].p_flags & 0x1 /* PF_X */) {
processor_->backend()->CommitExecutableRange(
virtual_addr, virtual_addr + phdr[i].p_memsz);
}
}
}
return true;
}
std::unique_ptr<Function> ElfModule::CreateFunction(uint32_t address) {
return std::unique_ptr<Function>(
processor_->backend()->CreateGuestFunction(this, address));
}
} // namespace cpu
} // namespace xe

View File

@@ -0,0 +1,55 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2015 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_CPU_ELF_MODULE_H_
#define XENIA_CPU_ELF_MODULE_H_
#include <vector>
#include "xenia/cpu/module.h"
namespace xe {
namespace kernel {
class KernelState;
} // namespace kernel
namespace cpu {
// ELF module: Used to load libxenon executables.
class ElfModule : public xe::cpu::Module {
public:
ElfModule(Processor* processor, kernel::KernelState* kernel_state);
virtual ~ElfModule();
bool loaded() const { return loaded_; }
uint32_t entry_point() const { return entry_point_; }
const std::string& name() const { return name_; }
const std::string& path() const { return path_; }
bool Load(const std::string& name, const std::string& path,
const void* elf_addr, size_t elf_length);
bool Unload();
protected:
std::unique_ptr<Function> CreateFunction(uint32_t address) override;
private:
std::string name_;
std::string path_;
kernel::KernelState* kernel_state_;
bool loaded_;
std::vector<uint8_t> elf_header_mem_; // Holds the ELF header
uint32_t entry_point_;
};
} // namespace cpu
} // namespace xe
#endif // XENIA_CPU_ELF_MODULE_H_