mirror of
https://github.com/InoriRus/Kyty.git
synced 2026-08-28 05:06:40 +00:00
load param.sfo
This commit is contained in:
@@ -0,0 +1,309 @@
|
||||
#ifndef EMULATOR_INCLUDE_EMULATOR_LOADER_ELF_H_
|
||||
#define EMULATOR_INCLUDE_EMULATOR_LOADER_ELF_H_
|
||||
|
||||
#include "Kyty/Core/Common.h"
|
||||
#include "Kyty/Core/String.h"
|
||||
#include "Kyty/Core/Vector.h"
|
||||
|
||||
#include "Emulator/Common.h"
|
||||
|
||||
namespace Kyty::Core {
|
||||
class File;
|
||||
} // namespace Kyty::Core
|
||||
|
||||
#ifdef KYTY_EMU_ENABLED
|
||||
|
||||
namespace Kyty::Loader {
|
||||
|
||||
using Elf64_Addr = uint64_t; // Unsigned program address
|
||||
using Elf64_Off = uint64_t; // Unsigned file offset
|
||||
using Elf64_Half = uint16_t; // Unsigned medium integer
|
||||
using Elf64_Word = uint32_t; // Unsigned integer
|
||||
using Elf64_Sword = int32_t; // Signed integer
|
||||
using Elf64_Xword = uint64_t; // Unsigned long integer
|
||||
using Elf64_Sxword = int64_t; // Signed long integer
|
||||
|
||||
constexpr int EI_MAG0 = 0;
|
||||
constexpr int EI_MAG1 = 1;
|
||||
constexpr int EI_MAG2 = 2;
|
||||
constexpr int EI_MAG3 = 3;
|
||||
constexpr int EI_CLASS = 4;
|
||||
constexpr int EI_DATA = 5;
|
||||
constexpr int EI_VERSION = 6;
|
||||
constexpr int EI_OSABI = 7;
|
||||
constexpr int EI_ABIVERSION = 8;
|
||||
constexpr int EI_PAD = 9;
|
||||
constexpr int EI_NIDENT = 16;
|
||||
|
||||
constexpr char ELFCLASS64 = 2; // 64-bit objects
|
||||
|
||||
constexpr char ELFDATA2LSB = 1; // Object file data structures are little-endian
|
||||
|
||||
constexpr Elf64_Half EM_X86_64 = 62; /* AMD x86-64 architecture */
|
||||
|
||||
constexpr int EV_CURRENT = 1;
|
||||
|
||||
constexpr char ELFOSABI_FREEBSD = 9; // FreeBSD operating system
|
||||
|
||||
constexpr Elf64_Half ET_DYNEXEC = 0xfe10; // Executable file
|
||||
constexpr Elf64_Half ET_DYNAMIC = 0xfe18; // Shared
|
||||
|
||||
//#define SHT_PROGBITS 1
|
||||
|
||||
constexpr Elf64_Word PT_LOAD = 1;
|
||||
constexpr Elf64_Word PT_DYNAMIC = 2;
|
||||
constexpr Elf64_Word PT_TLS = 7;
|
||||
constexpr Elf64_Word PT_OS_DYNLIBDATA = 0x61000000;
|
||||
constexpr Elf64_Word PT_OS_PROCPARAM = 0x61000001;
|
||||
constexpr Elf64_Word PT_OS_RELRO = 0x61000010;
|
||||
|
||||
constexpr Elf64_Word PF_X = 0x1; // Execute
|
||||
constexpr Elf64_Word PF_W = 0x2; // Write
|
||||
constexpr Elf64_Word PF_R = 0x4; // Read
|
||||
|
||||
constexpr Elf64_Sxword DT_DEBUG = 0x00000015;
|
||||
constexpr Elf64_Sxword DT_FINI = 0x0000000d;
|
||||
constexpr Elf64_Sxword DT_FINI_ARRAY = 0x0000001a;
|
||||
constexpr Elf64_Sxword DT_FINI_ARRAYSZ = 0x0000001c;
|
||||
constexpr Elf64_Sxword DT_FLAGS = 0x0000001e;
|
||||
constexpr Elf64_Sxword DT_INIT = 0x0000000c;
|
||||
constexpr Elf64_Sxword DT_INIT_ARRAY = 0x00000019;
|
||||
constexpr Elf64_Sxword DT_INIT_ARRAYSZ = 0x0000001b;
|
||||
constexpr Elf64_Sxword DT_NEEDED = 0x00000001;
|
||||
constexpr Elf64_Sxword DT_OS_EXPORT_LIB = 0x61000013;
|
||||
constexpr Elf64_Sxword DT_OS_EXPORT_LIB_1 = 0x61000047;
|
||||
constexpr Elf64_Sxword DT_OS_EXPORT_LIB_ATTR = 0x61000017;
|
||||
constexpr Elf64_Sxword DT_OS_FINGERPRINT = 0x61000007;
|
||||
constexpr Elf64_Sxword DT_OS_HASH = 0x61000025;
|
||||
constexpr Elf64_Sxword DT_OS_HASHSZ = 0x6100003d;
|
||||
constexpr Elf64_Sxword DT_OS_IMPORT_LIB = 0x61000015;
|
||||
constexpr Elf64_Sxword DT_OS_IMPORT_LIB_1 = 0x61000049;
|
||||
constexpr Elf64_Sxword DT_OS_IMPORT_LIB_ATTR = 0x61000019;
|
||||
constexpr Elf64_Sxword DT_OS_JMPREL = 0x61000029;
|
||||
constexpr Elf64_Sxword DT_OS_MODULE_ATTR = 0x61000011;
|
||||
constexpr Elf64_Sxword DT_OS_MODULE_INFO = 0x6100000d;
|
||||
constexpr Elf64_Sxword DT_OS_MODULE_INFO_1 = 0x61000043;
|
||||
constexpr Elf64_Sxword DT_OS_NEEDED_MODULE = 0x6100000f;
|
||||
constexpr Elf64_Sxword DT_OS_NEEDED_MODULE_1 = 0x61000045;
|
||||
constexpr Elf64_Sxword DT_OS_ORIGINAL_FILENAME = 0x61000009;
|
||||
constexpr Elf64_Sxword DT_OS_ORIGINAL_FILENAME_1 = 0x61000041;
|
||||
constexpr Elf64_Sxword DT_OS_PLTGOT = 0x61000027;
|
||||
constexpr Elf64_Sxword DT_OS_PLTREL = 0x6100002b;
|
||||
constexpr Elf64_Sxword DT_OS_PLTRELSZ = 0x6100002d;
|
||||
constexpr Elf64_Sxword DT_OS_RELA = 0x6100002f;
|
||||
constexpr Elf64_Sxword DT_OS_RELAENT = 0x61000033;
|
||||
constexpr Elf64_Sxword DT_OS_RELASZ = 0x61000031;
|
||||
constexpr Elf64_Sxword DT_OS_STRSZ = 0x61000037;
|
||||
constexpr Elf64_Sxword DT_OS_STRTAB = 0x61000035;
|
||||
constexpr Elf64_Sxword DT_OS_SYMENT = 0x6100003b;
|
||||
constexpr Elf64_Sxword DT_OS_SYMTAB = 0x61000039;
|
||||
constexpr Elf64_Sxword DT_OS_SYMTABSZ = 0x6100003f;
|
||||
constexpr Elf64_Sxword DT_PREINIT_ARRAY = 0x00000020;
|
||||
constexpr Elf64_Sxword DT_PREINIT_ARRAYSZ = 0x00000021;
|
||||
constexpr Elf64_Sxword DT_REL = 0x00000011;
|
||||
constexpr Elf64_Sxword DT_RELA = 0x00000007;
|
||||
constexpr Elf64_Sxword DT_SONAME = 0x0000000e;
|
||||
constexpr Elf64_Sxword DT_TEXTREL = 0x00000016;
|
||||
|
||||
constexpr Elf64_Sxword DT_HASH = 0x00000004;
|
||||
constexpr Elf64_Sxword DT_STRTAB = 0x00000005;
|
||||
constexpr Elf64_Sxword DT_STRSZ = 0x0000000a;
|
||||
constexpr Elf64_Sxword DT_SYMTAB = 0x00000006;
|
||||
constexpr Elf64_Sxword DT_SYMENT = 0x0000000b;
|
||||
constexpr Elf64_Sxword DT_PLTGOT = 0x00000003;
|
||||
constexpr Elf64_Sxword DT_PLTREL = 0x00000014;
|
||||
constexpr Elf64_Sxword DT_JMPREL = 0x00000017;
|
||||
constexpr Elf64_Sxword DT_PLTRELSZ = 0x00000002;
|
||||
constexpr Elf64_Sxword DT_RELASZ = 0x00000008;
|
||||
constexpr Elf64_Sxword DT_RELAENT = 0x00000009;
|
||||
constexpr Elf64_Sxword DT_RELACOUNT = 0x6ffffff9;
|
||||
|
||||
constexpr Elf64_Sxword DT_NULL = 0;
|
||||
|
||||
constexpr Elf64_Word R_X86_64_64 = 1;
|
||||
constexpr Elf64_Word R_X86_64_GLOB_DAT = 6;
|
||||
constexpr Elf64_Word R_X86_64_JUMP_SLOT = 7;
|
||||
constexpr Elf64_Word R_X86_64_RELATIVE = 8;
|
||||
constexpr Elf64_Word R_X86_64_DTPMOD64 = 16;
|
||||
|
||||
constexpr uint8_t STB_LOCAL = 0;
|
||||
constexpr uint8_t STB_GLOBAL = 1;
|
||||
constexpr uint8_t STB_WEAK = 2;
|
||||
|
||||
constexpr uint8_t STT_NOTYPE = 0;
|
||||
constexpr uint8_t STT_OBJECT = 1;
|
||||
constexpr uint8_t STT_FUNC = 2;
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
struct SelfHeader
|
||||
{
|
||||
uint8_t ident[12];
|
||||
uint16_t size1;
|
||||
uint16_t size2;
|
||||
uint64_t file_size;
|
||||
uint16_t segments_num;
|
||||
uint16_t unknown;
|
||||
uint32_t pad;
|
||||
};
|
||||
|
||||
struct SelfSegment
|
||||
{
|
||||
uint64_t type;
|
||||
uint64_t offset;
|
||||
uint64_t compressed_size;
|
||||
uint64_t decompressed_size;
|
||||
};
|
||||
|
||||
struct Elf64_Ehdr // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
uint8_t e_ident[EI_NIDENT]; /* ELF identification */
|
||||
Elf64_Half e_type; /* Object file type */
|
||||
Elf64_Half e_machine; /* Machine type */
|
||||
Elf64_Word e_version; /* Object file version */
|
||||
Elf64_Addr e_entry; /* Entry point address */
|
||||
Elf64_Off e_phoff; /* Program header offset */
|
||||
Elf64_Off e_shoff; /* Section header offset */
|
||||
Elf64_Word e_flags; /* Processor-specific flags */
|
||||
Elf64_Half e_ehsize; /* ELF header size */
|
||||
Elf64_Half e_phentsize; /* Size of program header entry */
|
||||
Elf64_Half e_phnum; /* Number of program header entries */
|
||||
Elf64_Half e_shentsize; /* Size of section header entry */
|
||||
Elf64_Half e_shnum; /* Number of section header entries */
|
||||
Elf64_Half e_shstrndx; /* Section name string table index */
|
||||
};
|
||||
|
||||
struct Elf64_Phdr // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
Elf64_Word p_type; /* Type of segment */
|
||||
Elf64_Word p_flags; /* Segment attributes */
|
||||
Elf64_Off p_offset; /* Offset in file */
|
||||
Elf64_Addr p_vaddr; /* Virtual address in memory */
|
||||
Elf64_Addr p_paddr; /* Reserved */
|
||||
Elf64_Xword p_filesz; /* Size of segment in file */
|
||||
Elf64_Xword p_memsz; /* Size of segment in memory */
|
||||
Elf64_Xword p_align; /* Alignment of segment */
|
||||
};
|
||||
|
||||
struct Elf64_Shdr // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
Elf64_Word sh_name; /* Section name */
|
||||
Elf64_Word sh_type; /* Section type */
|
||||
Elf64_Xword sh_flags; /* Section attributes */
|
||||
Elf64_Addr sh_addr; /* Virtual address in memory */
|
||||
Elf64_Off sh_offset; /* Offset in file */
|
||||
Elf64_Xword sh_size; /* Size of section */
|
||||
Elf64_Word sh_link; /* Link to other section */
|
||||
Elf64_Word sh_info; /* Miscellaneous information */
|
||||
Elf64_Xword sh_addralign; /* Address alignment boundary */
|
||||
Elf64_Xword sh_entsize; /* Size of entries, if section has table */
|
||||
};
|
||||
|
||||
struct Elf64_Dyn // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
Elf64_Sxword d_tag;
|
||||
union
|
||||
{
|
||||
Elf64_Xword d_val;
|
||||
Elf64_Addr d_ptr;
|
||||
} d_un;
|
||||
};
|
||||
|
||||
struct Elf64_Sym // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
[[nodiscard]] unsigned char GetBind() const { return st_info >> 4u; }
|
||||
[[nodiscard]] unsigned char GetType() const { return st_info & 0xfu; }
|
||||
|
||||
Elf64_Word st_name;
|
||||
unsigned char st_info;
|
||||
unsigned char st_other;
|
||||
Elf64_Half st_shndx;
|
||||
Elf64_Addr st_value;
|
||||
Elf64_Xword st_size;
|
||||
};
|
||||
|
||||
// struct Elf64_Rel // NOLINT(readability-identifier-naming)
|
||||
//{
|
||||
// Elf64_Addr r_offset;
|
||||
// Elf64_Xword r_info;
|
||||
//};
|
||||
|
||||
struct Elf64_Rela // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
[[nodiscard]] Elf64_Word GetSymbol() const { return static_cast<Elf64_Word>(r_info >> 32u); }
|
||||
[[nodiscard]] Elf64_Word GetType() const { return static_cast<Elf64_Word>(r_info & 0xffffffff); }
|
||||
|
||||
Elf64_Addr r_offset;
|
||||
Elf64_Xword r_info;
|
||||
Elf64_Sxword r_addend;
|
||||
};
|
||||
|
||||
struct tls_info_t // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
uint64_t addr;
|
||||
uint64_t filesz;
|
||||
uint64_t memsz;
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
||||
class Elf64
|
||||
{
|
||||
public:
|
||||
Elf64() = default;
|
||||
virtual ~Elf64();
|
||||
|
||||
void Open(const String& file_name);
|
||||
void Save(const String& file_name);
|
||||
|
||||
void DbgDump(const String& folder);
|
||||
|
||||
const char* GetSectionName(int index) { return m_str_table + m_shdr[index].sh_name; }
|
||||
|
||||
[[nodiscard]] bool IsSelf() const;
|
||||
[[nodiscard]] bool IsValid() const;
|
||||
[[nodiscard]] bool IsShared() const;
|
||||
[[nodiscard]] bool IsNextGen() const;
|
||||
|
||||
void LoadSegment(uint64_t vaddr, uint64_t file_offset, uint64_t size);
|
||||
|
||||
uint64_t GetEntry();
|
||||
|
||||
[[nodiscard]] const Elf64_Dyn* GetDynValue(Elf64_Sxword tag) const;
|
||||
[[nodiscard]] Vector<const Elf64_Dyn*> GetDynList(Elf64_Sxword tag) const;
|
||||
[[nodiscard]] bool HasDynValue(Elf64_Sxword tag) const { return GetDynValue(tag) != nullptr; }
|
||||
|
||||
KYTY_CLASS_NO_COPY(Elf64);
|
||||
|
||||
[[nodiscard]] const Elf64_Dyn* GetDynamic() const { return static_cast<Elf64_Dyn*>(m_dynamic); }
|
||||
[[nodiscard]] const Elf64_Ehdr* GetEhdr() const { return m_ehdr; }
|
||||
[[nodiscard]] const Elf64_Phdr* GetPhdr() const { return m_phdr; }
|
||||
[[nodiscard]] const Elf64_Shdr* GetShdr() const { return m_shdr; }
|
||||
[[nodiscard]] char* GetStrTable() const { return m_str_table; }
|
||||
|
||||
template <class T>
|
||||
[[nodiscard]] T GetDynamicData(uint64_t offset) const
|
||||
{
|
||||
return (m_dynamic_data == nullptr ? nullptr : reinterpret_cast<T>(static_cast<uint8_t*>(m_dynamic_data) + offset));
|
||||
}
|
||||
|
||||
private:
|
||||
void Clear();
|
||||
|
||||
Core::File* m_f = nullptr;
|
||||
SelfHeader* m_self = nullptr;
|
||||
SelfSegment* m_self_segments = nullptr;
|
||||
Elf64_Ehdr* m_ehdr = nullptr;
|
||||
Elf64_Phdr* m_phdr = nullptr;
|
||||
Elf64_Shdr* m_shdr = nullptr;
|
||||
void* m_dynamic = nullptr;
|
||||
void* m_dynamic_data = nullptr;
|
||||
char* m_str_table = nullptr;
|
||||
// uint64_t m_base_vaddr = 0;
|
||||
};
|
||||
|
||||
} // namespace Kyty::Loader
|
||||
|
||||
#endif // KYTY_EMU_ENABLED
|
||||
|
||||
#endif /* EMULATOR_INCLUDE_EMULATOR_LOADER_ELF_H_ */
|
||||
@@ -0,0 +1,150 @@
|
||||
#ifndef EMULATOR_INCLUDE_EMULATOR_LOADER_JIT_H_
|
||||
#define EMULATOR_INCLUDE_EMULATOR_LOADER_JIT_H_
|
||||
|
||||
#include "Emulator/Common.h"
|
||||
|
||||
#ifdef KYTY_EMU_ENABLED
|
||||
|
||||
namespace Kyty::Loader::Jit {
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
struct JmpWithIndex
|
||||
{
|
||||
void SetIndex(uint32_t index) { *reinterpret_cast<uint32_t*>(&code[1]) = index; }
|
||||
|
||||
void SetFunc(void* handler)
|
||||
{
|
||||
auto func_addr = reinterpret_cast<int64_t>(handler);
|
||||
auto rip_addr = reinterpret_cast<int64_t>(&code[10]);
|
||||
auto offset64 = func_addr - rip_addr;
|
||||
auto offset32 = static_cast<uint32_t>(static_cast<uint64_t>(offset64) & 0xffffffffu);
|
||||
|
||||
*reinterpret_cast<uint32_t*>(&code[6]) = offset32;
|
||||
}
|
||||
|
||||
static uint64_t GetSize() { return 16; }
|
||||
|
||||
// 68 00 00 00 00 push <index>
|
||||
// E9 E0 FF FF FF jmp <handler>
|
||||
uint8_t code[16] = {0x68, 0x00, 0x00, 0x00, 0x00, 0xE9, 0x00, 0x00, 0x00, 0x00, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90};
|
||||
};
|
||||
|
||||
struct CallPlt
|
||||
{
|
||||
explicit CallPlt(uint32_t table_size)
|
||||
{
|
||||
for (uint32_t index = 0; index < table_size; index++)
|
||||
{
|
||||
auto* c = new (&code[32] + JmpWithIndex::GetSize() * index) JmpWithIndex;
|
||||
c->SetIndex(index);
|
||||
c->SetFunc(this);
|
||||
}
|
||||
}
|
||||
|
||||
void SetPltGot(uint64_t vaddr) { *reinterpret_cast<uint64_t*>(&code[2]) = vaddr; }
|
||||
|
||||
uint64_t GetAddr(uint32_t index) { return reinterpret_cast<uint64_t>(&code[32] + JmpWithIndex::GetSize() * index); }
|
||||
|
||||
static uint64_t GetSize(uint32_t table_size) { return 32 + JmpWithIndex::GetSize() * table_size; }
|
||||
|
||||
// 0: 49 bb 88 77 66 55 44 movabs r11,0x1122334455667788
|
||||
// 7: 33 22 11
|
||||
// a: 41 ff 73 08 push QWORD PTR [r11+0x8]
|
||||
// e: 41 ff 63 10 jmp QWORD PTR [r11+0x10]
|
||||
uint8_t code[32] = {0x49, 0xBB, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x41, 0xFF,
|
||||
0x73, 0x08, 0x41, 0xFF, 0x63, 0x10, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90};
|
||||
};
|
||||
|
||||
struct JmpRax
|
||||
{
|
||||
template <class Handler>
|
||||
void SetFunc(Handler func)
|
||||
{
|
||||
*reinterpret_cast<Handler*>(&code[2]) = func;
|
||||
}
|
||||
|
||||
// mov rax, 0x1122334455667788
|
||||
// jmp rax
|
||||
uint8_t code[16] = {0x48, 0xB8, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0xFF, 0xE0};
|
||||
};
|
||||
|
||||
struct Call9
|
||||
{
|
||||
template <class Handler>
|
||||
void SetFunc(Handler func)
|
||||
{
|
||||
auto func_addr = reinterpret_cast<int64_t>(reinterpret_cast<void*>(func));
|
||||
auto rip_addr = reinterpret_cast<int64_t>(&code[5]);
|
||||
auto offset64 = func_addr - rip_addr;
|
||||
auto offset32 = static_cast<uint32_t>(static_cast<uint64_t>(offset64) & 0xffffffffu);
|
||||
|
||||
*reinterpret_cast<uint32_t*>(&code[1]) = offset32;
|
||||
}
|
||||
|
||||
static uint64_t GetSize() { return 9; }
|
||||
|
||||
// call func
|
||||
// mov rax,rax
|
||||
// nop
|
||||
uint8_t code[9] = {0xE8, 0x00, 0x00, 0x00, 0x00, 0x48, 0x89, 0xC0, 0x90};
|
||||
};
|
||||
|
||||
struct SafeCall
|
||||
{
|
||||
using func_t = KYTY_MS_ABI uint8_t* (*)();
|
||||
|
||||
void SetFunc(func_t func) { *reinterpret_cast<func_t*>(&code[0x22]) = func; }
|
||||
void SetRegSaveArea(uint8_t* area) { *reinterpret_cast<uint8_t**>(&code[0x18]) = area; }
|
||||
void SetLockVar(uint8_t* lock_var) { *reinterpret_cast<uint8_t**>(&code[0x0e]) = lock_var; }
|
||||
|
||||
static uint64_t GetSize() { return 0x1000; }
|
||||
|
||||
uint8_t code[0x6c] = {
|
||||
/*00*/ 0x51, // push rcx /* Save general purpose registers */
|
||||
/*01*/ 0x52, // push rdx
|
||||
/*02*/ 0x41, 0x50, // push r8
|
||||
/*04*/ 0x41, 0x51, // push r9
|
||||
/*06*/ 0x41, 0x52, // push r10
|
||||
/*08*/ 0x41, 0x53, // push r11
|
||||
/*0a*/ 0x57, // push rdi
|
||||
/*0b*/ 0x56, // push rsi
|
||||
/*0c*/ 0x48, 0xbf, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, // movabs rdi,0x1122334455667788
|
||||
/*16*/ 0x48, 0xbe, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, // movabs rsi,0x1122334455667788
|
||||
/*20*/ 0x48, 0xb9, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, // movabs rcx,0x1122334455667788
|
||||
/*2a*/ 0xb0, 0x01, // mov al,0x1 /* Lock */
|
||||
/*2c*/ 0x86, 0x07, // xchg BYTE PTR [rdi],al
|
||||
/*2e*/ 0x84, 0xc0, // test al,al
|
||||
/*30*/ 0x75, 0xf8, // jne 2a <LOCK>
|
||||
/*32*/ 0xb8, 0xff, 0xff, 0xff, 0xff, // mov eax,0xffffffff
|
||||
/*37*/ 0xba, 0xff, 0xff, 0xff, 0xff, // mov edx,0xffffffff
|
||||
/*3c*/ 0x0f, 0xae, 0x26, // xsave [rsi] /* Save float registers */
|
||||
/*3f*/ 0x48, 0x83, 0xec, 0x08, // sub rsp,0x8 /* Align stack */
|
||||
/*43*/ 0xff, 0xd1, // call rcx
|
||||
/*45*/ 0x48, 0x83, 0xc4, 0x08, // add rsp,0x8
|
||||
/*49*/ 0x48, 0x89, 0xc1, // mov rcx,rax
|
||||
/*4c*/ 0xb8, 0xff, 0xff, 0xff, 0xff, // mov eax,0xffffffff
|
||||
/*51*/ 0xba, 0xff, 0xff, 0xff, 0xff, // mov edx,0xffffffff
|
||||
/*56*/ 0x0f, 0xae, 0x2e, // xrstor [rsi] /* Restore float registers */
|
||||
/*59*/ 0x48, 0x89, 0xc8, // mov rax,rcx
|
||||
/*5c*/ 0xc6, 0x07, 0x00, // mov BYTE PTR [rdi],0x0 /* Unlock */
|
||||
/*5f*/ 0x5e, // pop rsi /* Restore general purpose registers */
|
||||
/*60*/ 0x5f, // pop rdi
|
||||
/*61*/ 0x41, 0x5b, // pop r11
|
||||
/*63*/ 0x41, 0x5a, // pop r10
|
||||
/*65*/ 0x41, 0x59, // pop r9
|
||||
/*67*/ 0x41, 0x58, // pop r8
|
||||
/*69*/ 0x5a, // pop rdx
|
||||
/*6a*/ 0x59, // pop rcx
|
||||
/*6b*/ 0xc3, // ret
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
||||
} // namespace Kyty::Loader::Jit
|
||||
|
||||
#endif // KYTY_EMU_ENABLED
|
||||
|
||||
#endif /* EMULATOR_INCLUDE_EMULATOR_LOADER_JIT_H_ */
|
||||
@@ -0,0 +1,27 @@
|
||||
#ifndef EMULATOR_INCLUDE_EMULATOR_LOADER_PARAM_H_
|
||||
#define EMULATOR_INCLUDE_EMULATOR_LOADER_PARAM_H_
|
||||
|
||||
#include "Kyty/Core/Common.h"
|
||||
#include "Kyty/Core/String.h"
|
||||
|
||||
#include "Emulator/Common.h"
|
||||
|
||||
#ifdef KYTY_EMU_ENABLED
|
||||
|
||||
namespace Kyty::Libs::Graphics {
|
||||
class Image;
|
||||
} // namespace Kyty::Libs::Graphics
|
||||
|
||||
namespace Kyty::Loader {
|
||||
|
||||
void ParamSfoLoad(const String& file_name);
|
||||
bool ParamSfoGetInt(const char* name, int32_t* value);
|
||||
bool ParamSfoGetString(const char* name, String* value);
|
||||
bool ParamSfoGetString(const char* name, char* value, size_t value_size);
|
||||
Libs::Graphics::Image* ParamSfoGetIcon();
|
||||
|
||||
} // namespace Kyty::Loader
|
||||
|
||||
#endif // KYTY_EMU_ENABLED
|
||||
|
||||
#endif /* EMULATOR_INCLUDE_EMULATOR_LOADER_PARAM_H_ */
|
||||
@@ -0,0 +1,189 @@
|
||||
#ifndef EMULATOR_INCLUDE_EMULATOR_LOADER_RUNTIMELINKER_H_
|
||||
#define EMULATOR_INCLUDE_EMULATOR_LOADER_RUNTIMELINKER_H_
|
||||
|
||||
#include "Kyty/Core/Common.h"
|
||||
#include "Kyty/Core/Hashmap.h"
|
||||
#include "Kyty/Core/String.h"
|
||||
#include "Kyty/Core/Threads.h"
|
||||
#include "Kyty/Core/Vector.h"
|
||||
|
||||
#include "Emulator/Common.h"
|
||||
#include "Emulator/Loader/SymbolDatabase.h"
|
||||
|
||||
#ifdef KYTY_EMU_ENABLED
|
||||
|
||||
namespace Kyty::Loader {
|
||||
|
||||
class Elf64;
|
||||
struct Elf64_Sym;
|
||||
struct Elf64_Rela;
|
||||
class RuntimeLinker;
|
||||
|
||||
namespace VirtualMemory {
|
||||
class ExceptionHandler;
|
||||
} // namespace VirtualMemory
|
||||
|
||||
using module_func_t = int (*)(size_t args, const void* argp);
|
||||
|
||||
struct ModuleId
|
||||
{
|
||||
bool operator==(const ModuleId& other) const
|
||||
{
|
||||
return version_major == other.version_major && version_minor == other.version_minor && name == other.name;
|
||||
}
|
||||
|
||||
String id;
|
||||
int version_major;
|
||||
int version_minor;
|
||||
String name;
|
||||
};
|
||||
|
||||
struct LibraryId
|
||||
{
|
||||
bool operator==(const LibraryId& other) const { return version == other.version && name == other.name; }
|
||||
|
||||
String id;
|
||||
int version;
|
||||
String name;
|
||||
};
|
||||
|
||||
struct ThreadLocalStorage
|
||||
{
|
||||
uint64_t image_vaddr = 0;
|
||||
uint64_t image_size = 0;
|
||||
uint64_t handler_vaddr = 0;
|
||||
|
||||
Core::Hashmap<int, uint8_t*> tlss;
|
||||
Core::Mutex mutex;
|
||||
};
|
||||
|
||||
struct DynamicInfo
|
||||
{
|
||||
void* hash_table = nullptr;
|
||||
uint64_t hash_table_size = 0;
|
||||
|
||||
char* str_table = nullptr;
|
||||
uint64_t str_table_size = 0;
|
||||
|
||||
Elf64_Sym* symbol_table = nullptr;
|
||||
uint64_t symbol_table_total_size = 0;
|
||||
uint64_t symbol_table_entry_size = 0;
|
||||
|
||||
uint64_t init_vaddr = 0;
|
||||
uint64_t fini_vaddr = 0;
|
||||
uint64_t init_array_vaddr = 0;
|
||||
uint64_t fini_array_vaddr = 0;
|
||||
uint64_t preinit_array_vaddr = 0;
|
||||
uint64_t init_array_size = 0;
|
||||
uint64_t fini_array_size = 0;
|
||||
uint64_t preinit_array_size = 0;
|
||||
uint64_t pltgot_vaddr = 0;
|
||||
|
||||
Elf64_Rela* jmprela_table = nullptr;
|
||||
uint64_t jmprela_table_size = 0;
|
||||
|
||||
Elf64_Rela* rela_table = nullptr;
|
||||
uint64_t rela_table_total_size = 0;
|
||||
uint64_t rela_table_entry_size = 0;
|
||||
|
||||
uint64_t relative_count = 0;
|
||||
|
||||
uint64_t debug = 0;
|
||||
uint64_t textrel = 0;
|
||||
uint64_t flags = 0;
|
||||
|
||||
const char* so_name = nullptr;
|
||||
|
||||
Vector<const char*> needed;
|
||||
Vector<ModuleId> export_modules;
|
||||
Vector<ModuleId> import_modules;
|
||||
Vector<LibraryId> export_libs;
|
||||
Vector<LibraryId> import_libs;
|
||||
};
|
||||
|
||||
struct Program
|
||||
{
|
||||
int32_t unique_id = -1;
|
||||
RuntimeLinker* rt = nullptr;
|
||||
String file_name;
|
||||
Elf64* elf = nullptr;
|
||||
VirtualMemory::ExceptionHandler* exception_handler = nullptr;
|
||||
DynamicInfo* dynamic_info = nullptr;
|
||||
uint64_t base_vaddr = 0;
|
||||
uint64_t base_size = 0;
|
||||
uint64_t base_size_aligned = 0;
|
||||
SymbolDatabase* export_symbols = nullptr;
|
||||
SymbolDatabase* import_symbols = nullptr;
|
||||
ThreadLocalStorage tls;
|
||||
bool fail_if_global_not_resolved = true;
|
||||
bool dbg_print_reloc = false;
|
||||
uint64_t proc_param_vaddr = 0;
|
||||
uint64_t custom_call_plt_vaddr = 0;
|
||||
uint32_t custom_call_plt_num = 0;
|
||||
};
|
||||
|
||||
class RuntimeLinker
|
||||
{
|
||||
public:
|
||||
RuntimeLinker();
|
||||
virtual ~RuntimeLinker();
|
||||
void Clear();
|
||||
|
||||
KYTY_CLASS_NO_COPY(RuntimeLinker);
|
||||
|
||||
void DbgDump(const String& folder);
|
||||
|
||||
Program* LoadProgram(const String& elf_name);
|
||||
void SaveMainProgram(const String& elf_name);
|
||||
void SaveProgram(Program* program, const String& elf_name);
|
||||
void UnloadProgram(Program* program);
|
||||
|
||||
[[nodiscard]] uint64_t GetEntry();
|
||||
[[nodiscard]] uint64_t GetProcParam();
|
||||
|
||||
void RelocateAll();
|
||||
|
||||
void Execute();
|
||||
int StartModule(Program* program, size_t args, const void* argp, module_func_t func);
|
||||
int StopModule(Program* program, size_t args, const void* argp, module_func_t func);
|
||||
void StartAllModules();
|
||||
void StopAllModules();
|
||||
void DeleteTlss(int thread_id);
|
||||
|
||||
void Resolve(const String& name, SymbolType type, Program* program, SymbolRecord* out_info, bool* bind_self);
|
||||
|
||||
SymbolDatabase* Symbols() { return m_symbols; }
|
||||
|
||||
static uint64_t ReadFromElf(Program* program, uint64_t vaddr);
|
||||
Program* FindProgramByAddr(uint64_t vaddr);
|
||||
Program* FindProgramById(int32_t id);
|
||||
|
||||
static uint8_t* TlsGetAddr(Program* program);
|
||||
static void DeleteTls(Program* program, int thread_id);
|
||||
|
||||
void StackTrace(uint64_t frame_ptr);
|
||||
|
||||
private:
|
||||
static void LoadProgramToMemory(Program* program);
|
||||
static void ParseProgramDynamicInfo(Program* program);
|
||||
static void CreateSymbolDatabase(Program* program);
|
||||
static void Relocate(Program* program);
|
||||
static void DeleteProgram(Program* program);
|
||||
static void SetupTlsHandler(Program* program);
|
||||
|
||||
Program* FindProgram(const ModuleId& m, const LibraryId& l);
|
||||
|
||||
static const ModuleId* FindModule(const Program& program, const String& id);
|
||||
static const LibraryId* FindLibrary(const Program& program, const String& id);
|
||||
|
||||
Vector<Program*> m_programs;
|
||||
SymbolDatabase* m_symbols = nullptr;
|
||||
bool m_relocated = false;
|
||||
Core::Mutex m_mutex;
|
||||
};
|
||||
|
||||
} // namespace Kyty::Loader
|
||||
|
||||
#endif // KYTY_EMU_ENABLED
|
||||
|
||||
#endif /* EMULATOR_INCLUDE_EMULATOR_LOADER_RUNTIMELINKER_H_ */
|
||||
@@ -0,0 +1,68 @@
|
||||
#ifndef EMULATOR_INCLUDE_EMULATOR_LOADER_SYMBOLDATABASE_H_
|
||||
#define EMULATOR_INCLUDE_EMULATOR_LOADER_SYMBOLDATABASE_H_
|
||||
|
||||
#include "Kyty/Core/Common.h"
|
||||
#include "Kyty/Core/Hashmap.h"
|
||||
#include "Kyty/Core/String.h"
|
||||
#include "Kyty/Core/Vector.h"
|
||||
|
||||
#include "Emulator/Common.h"
|
||||
|
||||
#ifdef KYTY_EMU_ENABLED
|
||||
|
||||
namespace Kyty::Loader {
|
||||
|
||||
enum class SymbolType
|
||||
{
|
||||
Unknown,
|
||||
Func,
|
||||
Object,
|
||||
TlsModule,
|
||||
NoType,
|
||||
};
|
||||
|
||||
struct SymbolRecord
|
||||
{
|
||||
String name;
|
||||
String dbg_name;
|
||||
uint64_t vaddr;
|
||||
};
|
||||
|
||||
struct SymbolResolve
|
||||
{
|
||||
String name;
|
||||
String library;
|
||||
int library_version;
|
||||
String module;
|
||||
int module_version_major;
|
||||
int module_version_minor;
|
||||
SymbolType type;
|
||||
};
|
||||
|
||||
class SymbolDatabase
|
||||
{
|
||||
public:
|
||||
SymbolDatabase() = default;
|
||||
virtual ~SymbolDatabase() = default;
|
||||
|
||||
void Add(const SymbolResolve& s, uint64_t vaddr);
|
||||
void Add(const SymbolResolve& s, uint64_t vaddr, const String& dbg_name);
|
||||
|
||||
[[nodiscard]] const SymbolRecord* Find(const SymbolResolve& s) const;
|
||||
|
||||
void DbgDump(const String& folder, const String& file_name);
|
||||
|
||||
KYTY_CLASS_NO_COPY(SymbolDatabase);
|
||||
|
||||
static String GenerateName(const SymbolResolve& s);
|
||||
|
||||
private:
|
||||
Vector<SymbolRecord> m_symbols;
|
||||
Core::Hashmap<String, uint32_t> m_map;
|
||||
};
|
||||
|
||||
} // namespace Kyty::Loader
|
||||
|
||||
#endif // KYTY_EMU_ENABLED
|
||||
|
||||
#endif /* EMULATOR_INCLUDE_EMULATOR_LOADER_SYMBOLDATABASE_H_ */
|
||||
@@ -0,0 +1,26 @@
|
||||
#ifndef EMULATOR_INCLUDE_EMULATOR_LOADER_TIMER_H_
|
||||
#define EMULATOR_INCLUDE_EMULATOR_LOADER_TIMER_H_
|
||||
|
||||
#include "Kyty/Core/Common.h"
|
||||
#include "Kyty/Core/DateTime.h"
|
||||
#include "Kyty/Core/Subsystems.h"
|
||||
|
||||
#include "Emulator/Common.h"
|
||||
|
||||
#ifdef KYTY_EMU_ENABLED
|
||||
|
||||
namespace Kyty::Loader::Timer {
|
||||
|
||||
KYTY_SUBSYSTEM_DEFINE(Timer);
|
||||
|
||||
void Start();
|
||||
double GetTimeMs();
|
||||
Core::Time GetTime();
|
||||
uint64_t GetCounter();
|
||||
uint64_t GetFrequency();
|
||||
|
||||
} // namespace Kyty::Loader::Timer
|
||||
|
||||
#endif // KYTY_EMU_ENABLED
|
||||
|
||||
#endif /* EMULATOR_INCLUDE_EMULATOR_LOADER_TIMER_H_ */
|
||||
@@ -0,0 +1,115 @@
|
||||
#ifndef EMULATOR_INCLUDE_EMULATOR_LOADER_VIRTUALMEMORY_H_
|
||||
#define EMULATOR_INCLUDE_EMULATOR_LOADER_VIRTUALMEMORY_H_
|
||||
|
||||
#include "Kyty/Core/Common.h"
|
||||
#include "Kyty/Core/String.h"
|
||||
|
||||
#include "Emulator/Common.h"
|
||||
|
||||
#ifdef KYTY_EMU_ENABLED
|
||||
|
||||
namespace Kyty::Loader {
|
||||
|
||||
enum class ProcessorArchitecture
|
||||
{
|
||||
Unknown,
|
||||
Amd64, // x64 (AMD or Intel)
|
||||
};
|
||||
|
||||
struct SystemInfo
|
||||
{
|
||||
uint32_t PageSize;
|
||||
uint64_t MinimumApplicationAddress;
|
||||
uint64_t MaximumApplicationAddress;
|
||||
uint32_t ActiveProcessorMask;
|
||||
uint32_t NumberOfProcessors;
|
||||
ProcessorArchitecture ProcessorArchitecture;
|
||||
uint32_t AllocationGranularity;
|
||||
uint16_t ProcessorLevel;
|
||||
uint16_t ProcessorRevision;
|
||||
String ProcessorName;
|
||||
};
|
||||
|
||||
SystemInfo GetSystemInfo();
|
||||
|
||||
namespace VirtualMemory {
|
||||
|
||||
class ExceptionHandlerPrivate;
|
||||
|
||||
class ExceptionHandler
|
||||
{
|
||||
public:
|
||||
enum class ExceptionType
|
||||
{
|
||||
Unknown,
|
||||
AccessViolation
|
||||
};
|
||||
|
||||
enum class AccessViolationType
|
||||
{
|
||||
Unknown,
|
||||
Read,
|
||||
Write,
|
||||
Execute
|
||||
};
|
||||
|
||||
struct ExceptionInfo
|
||||
{
|
||||
ExceptionType type = ExceptionType::Unknown;
|
||||
AccessViolationType access_violation_type = AccessViolationType::Unknown;
|
||||
uint64_t access_violation_vaddr = 0;
|
||||
uint64_t exception_address = 0;
|
||||
uint64_t rbp = 0;
|
||||
};
|
||||
|
||||
using handler_func_t = void (*)(const ExceptionInfo*);
|
||||
|
||||
ExceptionHandler();
|
||||
virtual ~ExceptionHandler();
|
||||
|
||||
KYTY_CLASS_NO_COPY(ExceptionHandler);
|
||||
|
||||
static uint64_t GetSize();
|
||||
|
||||
bool Install(uint64_t base_address, uint64_t handler_addr, uint64_t image_size, handler_func_t func);
|
||||
bool Uninstall();
|
||||
|
||||
static bool InstallVectored(handler_func_t func);
|
||||
|
||||
private:
|
||||
ExceptionHandlerPrivate* m_p = nullptr;
|
||||
};
|
||||
|
||||
enum class Mode : uint32_t
|
||||
{
|
||||
NoAccess = 0,
|
||||
Read = 1,
|
||||
Write = 2,
|
||||
ReadWrite = Read | Write,
|
||||
Execute = 4,
|
||||
ExecuteRead = Execute | Read,
|
||||
ExecuteWrite = Execute | Write,
|
||||
ExecuteReadWrite = Execute | Read | Write,
|
||||
};
|
||||
|
||||
inline bool IsExecute(Mode mode)
|
||||
{
|
||||
return (mode == Mode::Execute || mode == Mode::ExecuteRead || mode == Mode::ExecuteWrite || mode == Mode::ExecuteReadWrite);
|
||||
}
|
||||
|
||||
void Init();
|
||||
|
||||
uint64_t Alloc(uint64_t address, uint64_t size, Mode mode);
|
||||
uint64_t AllocAligned(uint64_t address, uint64_t size, Mode mode, uint64_t alignment);
|
||||
bool Free(uint64_t address);
|
||||
bool Protect(uint64_t address, uint64_t size, Mode mode, Mode* old_mode = nullptr);
|
||||
bool FlushInstructionCache(uint64_t address, uint64_t size);
|
||||
bool PatchReplace(uint64_t vaddr, uint64_t value);
|
||||
|
||||
} // namespace VirtualMemory
|
||||
|
||||
} // namespace Kyty::Loader
|
||||
|
||||
#endif // KYTY_EMU_ENABLED
|
||||
|
||||
#endif /* EMULATOR_INCLUDE_EMULATOR_LOADER_VIRTUALMEMORY_H_ */
|
||||
Reference in New Issue
Block a user