linker: Cleanup
This commit is contained in:
parent
6f96a03c13
commit
6292525fa2
|
@ -12,7 +12,7 @@ void assert_fail_impl() {
|
|||
}
|
||||
|
||||
[[noreturn]] void unreachable_impl() {
|
||||
/*Common::Log::Stop();
|
||||
Common::Log::Stop();
|
||||
Crash();
|
||||
throw std::runtime_error("Unreachable code");*/
|
||||
throw std::runtime_error("Unreachable code");
|
||||
}
|
||||
|
|
|
@ -2,31 +2,29 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <Zydis/Zydis.h>
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/aerolib/aerolib.h"
|
||||
#include "core/aerolib/stubs.h"
|
||||
#include "core/hle/libraries/libkernel/thread_management.h"
|
||||
#include "core/linker.h"
|
||||
#include "core/tls.h"
|
||||
#include "core/virtual_memory.h"
|
||||
|
||||
namespace Core {
|
||||
|
||||
constexpr bool debug_loader = true;
|
||||
static constexpr u64 LoadAddress = SYSTEM_RESERVED + CODE_BASE_OFFSET;
|
||||
|
||||
static u64 g_load_addr = SYSTEM_RESERVED + CODE_BASE_OFFSET;
|
||||
|
||||
static u64 get_aligned_size(const elf_program_header& phdr) {
|
||||
static u64 GetAlignedSize(const elf_program_header& phdr) {
|
||||
return (phdr.p_align != 0 ? (phdr.p_memsz + (phdr.p_align - 1)) & ~(phdr.p_align - 1)
|
||||
: phdr.p_memsz);
|
||||
}
|
||||
|
||||
static u64 calculate_base_size(const elf_header& ehdr, std::span<const elf_program_header> phdr) {
|
||||
static u64 CalculateBaseSize(const elf_header& ehdr, std::span<const elf_program_header> phdr) {
|
||||
u64 base_size = 0;
|
||||
for (u16 i = 0; i < ehdr.e_phnum; i++) {
|
||||
if (phdr[i].p_memsz != 0 && (phdr[i].p_type == PT_LOAD || phdr[i].p_type == PT_SCE_RELRO)) {
|
||||
u64 last_addr = phdr[i].p_vaddr + get_aligned_size(phdr[i]);
|
||||
u64 last_addr = phdr[i].p_vaddr + GetAlignedSize(phdr[i]);
|
||||
if (last_addr > base_size) {
|
||||
base_size = last_addr;
|
||||
}
|
||||
|
@ -35,7 +33,7 @@ static u64 calculate_base_size(const elf_header& ehdr, std::span<const elf_progr
|
|||
return base_size;
|
||||
}
|
||||
|
||||
static std::string encodeId(u64 nVal) {
|
||||
static std::string EncodeId(u64 nVal) {
|
||||
std::string enc;
|
||||
const char pCodes[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-";
|
||||
if (nVal < 0x40u) {
|
||||
|
@ -67,7 +65,6 @@ Module* Linker::LoadModule(const std::filesystem::path& elf_name) {
|
|||
|
||||
auto& m = m_modules.emplace_back();
|
||||
m = std::make_unique<Module>();
|
||||
m->linker = this;
|
||||
m->elf.Open(elf_name);
|
||||
|
||||
if (m->elf.IsElfFile()) {
|
||||
|
@ -83,7 +80,7 @@ Module* Linker::LoadModule(const std::filesystem::path& elf_name) {
|
|||
return m.get();
|
||||
}
|
||||
|
||||
Module* Linker::FindModule(/*u32 id*/) {
|
||||
Module* Linker::FindModule(u32 id) {
|
||||
// TODO atm we only have 1 module so we don't need to iterate on vector
|
||||
if (m_modules.empty()) [[unlikely]] {
|
||||
return nullptr;
|
||||
|
@ -91,85 +88,17 @@ Module* Linker::FindModule(/*u32 id*/) {
|
|||
return m_modules[0].get();
|
||||
}
|
||||
|
||||
struct TLSPattern {
|
||||
uint8_t pattern[5];
|
||||
uint8_t pattern_size;
|
||||
uint8_t imm_size;
|
||||
uint8_t target_reg;
|
||||
};
|
||||
|
||||
constexpr static TLSPattern TlsPatterns[] = {
|
||||
{{0x64, 0x48, 0xA1},
|
||||
3,
|
||||
8,
|
||||
0}, // 64 48 A1 | 00 00 00 00 00 00 00 00 # mov rax, qword ptr fs:[64b imm]
|
||||
|
||||
{{0x64, 0x48, 0x8B, 0x4, 0x25},
|
||||
5,
|
||||
4,
|
||||
0}, // 64 48 8B 04 25 | 00 00 00 00 # mov rax,qword ptr fs:[0]
|
||||
{{0x64, 0x48, 0x8B, 0xC, 0x25}, 5, 4, 1}, // rcx
|
||||
{{0x64, 0x48, 0x8B, 0x14, 0x25}, 5, 4, 2}, // rdx
|
||||
{{0x64, 0x48, 0x8B, 0x1C, 0x25}, 5, 4, 3}, // rbx
|
||||
{{0x64, 0x48, 0x8B, 0x24, 0x25}, 5, 4, 4}, // rsp
|
||||
{{0x64, 0x48, 0x8B, 0x2C, 0x25}, 5, 4, 5}, // rbp
|
||||
{{0x64, 0x48, 0x8B, 0x34, 0x25}, 5, 4, 6}, // rsi
|
||||
{{0x64, 0x48, 0x8B, 0x3C, 0x25}, 5, 4, 7}, // rdi
|
||||
{{0x64, 0x4C, 0x8B, 0x4, 0x25}, 5, 4, 8}, // r8
|
||||
{{0x64, 0x4C, 0x8B, 0xC, 0x25}, 5, 4, 9}, // r9
|
||||
{{0x64, 0x4C, 0x8B, 0x14, 0x25}, 5, 4, 10}, // r10
|
||||
{{0x64, 0x4C, 0x8B, 0x1C, 0x25}, 5, 4, 11}, // r11
|
||||
{{0x64, 0x4C, 0x8B, 0x24, 0x25}, 5, 4, 12}, // r12
|
||||
{{0x64, 0x4C, 0x8B, 0x2C, 0x25}, 5, 4, 13}, // r13
|
||||
{{0x64, 0x4C, 0x8B, 0x34, 0x25}, 5, 4, 14}, // r14
|
||||
{{0x64, 0x4C, 0x8B, 0x3C, 0x25}, 5, 4, 15}, // r15
|
||||
};
|
||||
|
||||
void PatchTLS(u64 segment_addr, u64 segment_size) {
|
||||
u8* code = reinterpret_cast<u8*>(segment_addr);
|
||||
auto remaining_size = segment_size;
|
||||
|
||||
while (remaining_size) {
|
||||
for (const auto& tls_pattern : TlsPatterns) {
|
||||
const auto total_size = tls_pattern.pattern_size + tls_pattern.imm_size;
|
||||
if (remaining_size < total_size) {
|
||||
continue;
|
||||
}
|
||||
if (std::memcmp(code, tls_pattern.pattern, tls_pattern.pattern_size) != 0) {
|
||||
continue;
|
||||
}
|
||||
if (tls_pattern.imm_size == 4) {
|
||||
LOG_INFO(Core_Linker, "PATTERN32 FOUND at {}, reg: {} offset: {:#x}\n",
|
||||
fmt::ptr(code), tls_pattern.target_reg,
|
||||
*(u32*)(code + tls_pattern.pattern_size));
|
||||
} else {
|
||||
LOG_INFO(Core_Linker, "PATTERN64 FOUND at {}, reg: {} offset: {:#x}\n",
|
||||
fmt::ptr(code), tls_pattern.target_reg,
|
||||
*(u32*)(code + tls_pattern.pattern_size));
|
||||
}
|
||||
code[0] = 0xcd;
|
||||
code[1] = 0x80 + tls_pattern.target_reg;
|
||||
code[2] = tls_pattern.pattern_size | (tls_pattern.imm_size << 4);
|
||||
code += total_size - 1;
|
||||
remaining_size -= total_size - 1;
|
||||
break;
|
||||
}
|
||||
code++;
|
||||
remaining_size--;
|
||||
}
|
||||
}
|
||||
|
||||
void Linker::LoadModuleToMemory(Module* m) {
|
||||
// get elf header, program header
|
||||
const auto elf_header = m->elf.GetElfHeader();
|
||||
const auto elf_pheader = m->elf.GetProgramHeader();
|
||||
|
||||
u64 base_size = calculate_base_size(elf_header, elf_pheader);
|
||||
u64 base_size = CalculateBaseSize(elf_header, elf_pheader);
|
||||
m->aligned_base_size = (base_size & ~(static_cast<u64>(0x1000) - 1)) +
|
||||
0x1000; // align base size to 0x1000 block size (TODO is that the default
|
||||
// block size or it can be changed?
|
||||
|
||||
m->base_virtual_addr = VirtualMemory::memory_alloc(g_load_addr, m->aligned_base_size,
|
||||
m->base_virtual_addr = VirtualMemory::memory_alloc(LoadAddress, m->aligned_base_size,
|
||||
VirtualMemory::MemoryMode::ExecuteReadWrite);
|
||||
|
||||
LOG_INFO(Core_Linker, "====Load Module to Memory ========");
|
||||
|
@ -184,7 +113,7 @@ void Linker::LoadModuleToMemory(Module* m) {
|
|||
if (elf_pheader[i].p_memsz != 0) {
|
||||
u64 segment_addr = elf_pheader[i].p_vaddr + m->base_virtual_addr;
|
||||
u64 segment_file_size = elf_pheader[i].p_filesz;
|
||||
u64 segment_memory_size = get_aligned_size(elf_pheader[i]);
|
||||
u64 segment_memory_size = GetAlignedSize(elf_pheader[i]);
|
||||
auto segment_mode = m->elf.ElfPheaderFlagsStr(elf_pheader[i].p_flags);
|
||||
LOG_INFO(Core_Linker, "program header = [{}] type = {}", i,
|
||||
m->elf.ElfPheaderTypeStr(elf_pheader[i].p_type));
|
||||
|
@ -225,7 +154,7 @@ void Linker::LoadModuleToMemory(Module* m) {
|
|||
break;
|
||||
case PT_TLS:
|
||||
m->tls.image_virtual_addr = elf_pheader[i].p_vaddr + m->base_virtual_addr;
|
||||
m->tls.image_size = get_aligned_size(elf_pheader[i]);
|
||||
m->tls.image_size = GetAlignedSize(elf_pheader[i]);
|
||||
LOG_INFO(Core_Linker, "tls virtual address ={:#x}", m->tls.image_virtual_addr);
|
||||
LOG_INFO(Core_Linker, "tls image size ={}", m->tls.image_size);
|
||||
break;
|
||||
|
@ -352,14 +281,14 @@ void Linker::LoadDynamicInfo(Module* m) {
|
|||
ModuleInfo info{};
|
||||
info.value = dyn->d_un.d_val;
|
||||
info.name = m->dynamic_info.str_table + info.name_offset;
|
||||
info.enc_id = encodeId(info.id);
|
||||
info.enc_id = EncodeId(info.id);
|
||||
m->dynamic_info.import_modules.push_back(info);
|
||||
} break;
|
||||
case DT_SCE_IMPORT_LIB: {
|
||||
LibraryInfo info{};
|
||||
info.value = dyn->d_un.d_val;
|
||||
info.name = m->dynamic_info.str_table + info.name_offset;
|
||||
info.enc_id = encodeId(info.id);
|
||||
info.enc_id = EncodeId(info.id);
|
||||
m->dynamic_info.import_libs.push_back(info);
|
||||
} break;
|
||||
case DT_SCE_FINGERPRINT:
|
||||
|
@ -384,7 +313,7 @@ void Linker::LoadDynamicInfo(Module* m) {
|
|||
ModuleInfo info{};
|
||||
info.value = dyn->d_un.d_val;
|
||||
info.name = m->dynamic_info.str_table + info.name_offset;
|
||||
info.enc_id = encodeId(info.id);
|
||||
info.enc_id = EncodeId(info.id);
|
||||
m->dynamic_info.export_modules.push_back(info);
|
||||
} break;
|
||||
case DT_SCE_MODULE_ATTR:
|
||||
|
@ -396,7 +325,7 @@ void Linker::LoadDynamicInfo(Module* m) {
|
|||
LibraryInfo info{};
|
||||
info.value = dyn->d_un.d_val;
|
||||
info.name = m->dynamic_info.str_table + info.name_offset;
|
||||
info.enc_id = encodeId(info.id);
|
||||
info.enc_id = EncodeId(info.id);
|
||||
m->dynamic_info.export_libs.push_back(info);
|
||||
} break;
|
||||
default:
|
||||
|
@ -529,7 +458,9 @@ void Linker::LoadSymbols(Module* m) {
|
|||
}
|
||||
}
|
||||
}
|
||||
static void relocate(u32 idx, elf_relocation* rel, Module* m, bool isJmpRel) {
|
||||
|
||||
void Linker::Relocate(Module* m) {
|
||||
const auto relocate = [this](u32 idx, elf_relocation* rel, Module* m, bool isJmpRel) {
|
||||
auto type = rel->GetType();
|
||||
auto symbol = rel->GetSymbol();
|
||||
auto addend = rel->rel_addend;
|
||||
|
@ -579,7 +510,7 @@ static void relocate(u32 idx, elf_relocation* rel, Module* m, bool isJmpRel) {
|
|||
switch (sym_bind) {
|
||||
case STB_GLOBAL:
|
||||
rel_name = namesTlb + sym.st_name;
|
||||
m->linker->Resolve(rel_name, rel_sym_type, m, &symrec);
|
||||
Resolve(rel_name, rel_sym_type, m, &symrec);
|
||||
symbol_vitrual_addr = symrec.virtual_address;
|
||||
rel_isResolved = (symbol_vitrual_addr != 0);
|
||||
|
||||
|
@ -609,9 +540,8 @@ static void relocate(u32 idx, elf_relocation* rel, Module* m, bool isJmpRel) {
|
|||
} else {
|
||||
LOG_INFO(Core_Linker, "function not patched! {}", rel_name);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void Linker::Relocate(Module* m) {
|
||||
u32 idx = 0;
|
||||
for (auto* rel = m->dynamic_info.relocation_table;
|
||||
reinterpret_cast<u8*>(rel) < reinterpret_cast<u8*>(m->dynamic_info.relocation_table) +
|
||||
|
@ -678,7 +608,7 @@ static PS4_SYSV_ABI void ProgramExitFunc() {
|
|||
fmt::print("exit function called\n");
|
||||
}
|
||||
|
||||
static void run_main_entry(u64 addr, EntryParams* params, exit_func_t exit_func) {
|
||||
static void RunMainEntry(u64 addr, EntryParams* params, exit_func_t exit_func) {
|
||||
// reinterpret_cast<entry_func_t>(addr)(params, exit_func); // can't be used, stack has to have
|
||||
// a specific layout
|
||||
|
||||
|
@ -708,7 +638,7 @@ void Linker::Execute() {
|
|||
p.argv[0] = "eboot.bin"; // hmm should be ok?
|
||||
|
||||
const auto& module = m_modules.at(0);
|
||||
run_main_entry(module->elf.GetElfEntry() + module->base_virtual_addr, &p, ProgramExitFunc);
|
||||
RunMainEntry(module->elf.GetElfEntry() + module->base_virtual_addr, &p, ProgramExitFunc);
|
||||
}
|
||||
|
||||
} // namespace Core
|
||||
|
|
|
@ -51,6 +51,7 @@ struct PS4ThreadLocal {
|
|||
u64 image_size = 0;
|
||||
u64 handler_virtual_addr = 0;
|
||||
};
|
||||
|
||||
struct DynamicModuleInfo {
|
||||
void* hash_table = nullptr;
|
||||
u64 hash_table_size = 0;
|
||||
|
@ -97,9 +98,7 @@ struct DynamicModuleInfo {
|
|||
struct Module {
|
||||
Loader::Elf elf;
|
||||
u64 aligned_base_size = 0;
|
||||
u64 base_virtual_addr = 0; // Base virtual address
|
||||
|
||||
Linker* linker = nullptr;
|
||||
u64 base_virtual_addr = 0;
|
||||
|
||||
std::vector<u8> m_dynamic;
|
||||
std::vector<u8> m_dynamic_data;
|
||||
|
@ -117,7 +116,7 @@ public:
|
|||
virtual ~Linker();
|
||||
|
||||
Module* LoadModule(const std::filesystem::path& elf_name);
|
||||
Module* FindModule(/*u32 id*/);
|
||||
Module* FindModule(u32 id = 0);
|
||||
void LoadModuleToMemory(Module* m);
|
||||
void LoadDynamicInfo(Module* m);
|
||||
void LoadSymbols(Module* m);
|
||||
|
|
|
@ -9,6 +9,40 @@ namespace Core {
|
|||
|
||||
thread_local u8 TLS[1024];
|
||||
|
||||
struct TLSPattern {
|
||||
uint8_t pattern[5];
|
||||
uint8_t pattern_size;
|
||||
uint8_t imm_size;
|
||||
uint8_t target_reg;
|
||||
};
|
||||
|
||||
constexpr static TLSPattern TlsPatterns[] = {
|
||||
{{0x64, 0x48, 0xA1},
|
||||
3,
|
||||
8,
|
||||
0}, // 64 48 A1 | 00 00 00 00 00 00 00 00 # mov rax, qword ptr fs:[64b imm]
|
||||
|
||||
{{0x64, 0x48, 0x8B, 0x4, 0x25},
|
||||
5,
|
||||
4,
|
||||
0}, // 64 48 8B 04 25 | 00 00 00 00 # mov rax,qword ptr fs:[0]
|
||||
{{0x64, 0x48, 0x8B, 0xC, 0x25}, 5, 4, 1}, // rcx
|
||||
{{0x64, 0x48, 0x8B, 0x14, 0x25}, 5, 4, 2}, // rdx
|
||||
{{0x64, 0x48, 0x8B, 0x1C, 0x25}, 5, 4, 3}, // rbx
|
||||
{{0x64, 0x48, 0x8B, 0x24, 0x25}, 5, 4, 4}, // rsp
|
||||
{{0x64, 0x48, 0x8B, 0x2C, 0x25}, 5, 4, 5}, // rbp
|
||||
{{0x64, 0x48, 0x8B, 0x34, 0x25}, 5, 4, 6}, // rsi
|
||||
{{0x64, 0x48, 0x8B, 0x3C, 0x25}, 5, 4, 7}, // rdi
|
||||
{{0x64, 0x4C, 0x8B, 0x4, 0x25}, 5, 4, 8}, // r8
|
||||
{{0x64, 0x4C, 0x8B, 0xC, 0x25}, 5, 4, 9}, // r9
|
||||
{{0x64, 0x4C, 0x8B, 0x14, 0x25}, 5, 4, 10}, // r10
|
||||
{{0x64, 0x4C, 0x8B, 0x1C, 0x25}, 5, 4, 11}, // r11
|
||||
{{0x64, 0x4C, 0x8B, 0x24, 0x25}, 5, 4, 12}, // r12
|
||||
{{0x64, 0x4C, 0x8B, 0x2C, 0x25}, 5, 4, 13}, // r13
|
||||
{{0x64, 0x4C, 0x8B, 0x34, 0x25}, 5, 4, 14}, // r14
|
||||
{{0x64, 0x4C, 0x8B, 0x3C, 0x25}, 5, 4, 15}, // r15
|
||||
};
|
||||
|
||||
uintptr_t GetGuestTls(s64 tls_offset) {
|
||||
if (tls_offset == 0) {
|
||||
return reinterpret_cast<uintptr_t>(TLS);
|
||||
|
@ -103,4 +137,38 @@ void InstallTlsHandler() {
|
|||
#endif
|
||||
}
|
||||
|
||||
void PatchTLS(u64 segment_addr, u64 segment_size) {
|
||||
u8* code = reinterpret_cast<u8*>(segment_addr);
|
||||
auto remaining_size = segment_size;
|
||||
|
||||
while (remaining_size) {
|
||||
for (const auto& tls_pattern : TlsPatterns) {
|
||||
const auto total_size = tls_pattern.pattern_size + tls_pattern.imm_size;
|
||||
if (remaining_size < total_size) {
|
||||
continue;
|
||||
}
|
||||
if (std::memcmp(code, tls_pattern.pattern, tls_pattern.pattern_size) != 0) {
|
||||
continue;
|
||||
}
|
||||
if (tls_pattern.imm_size == 4) {
|
||||
LOG_INFO(Core_Linker, "PATTERN32 FOUND at {}, reg: {} offset: {:#x}",
|
||||
fmt::ptr(code), tls_pattern.target_reg,
|
||||
*(u32*)(code + tls_pattern.pattern_size));
|
||||
} else {
|
||||
LOG_INFO(Core_Linker, "PATTERN64 FOUND at {}, reg: {} offset: {:#x}",
|
||||
fmt::ptr(code), tls_pattern.target_reg,
|
||||
*(u32*)(code + tls_pattern.pattern_size));
|
||||
}
|
||||
code[0] = 0xcd;
|
||||
code[1] = 0x80 + tls_pattern.target_reg;
|
||||
code[2] = tls_pattern.pattern_size | (tls_pattern.imm_size << 4);
|
||||
code += total_size - 1;
|
||||
remaining_size -= total_size - 1;
|
||||
break;
|
||||
}
|
||||
code++;
|
||||
remaining_size--;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Core
|
||||
|
|
|
@ -3,8 +3,14 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "common/types.h"
|
||||
|
||||
namespace Core {
|
||||
|
||||
/// Installs a host exception handler to handle guest TLS access.
|
||||
void InstallTlsHandler();
|
||||
|
||||
/// Patches any instructions that access TLS to trigger the exception handler.
|
||||
void PatchTLS(u64 segment_addr, u64 segment_size);
|
||||
|
||||
} // namespace Core
|
||||
|
|
Loading…
Reference in New Issue