loader: preserve resolved relocations across dynamic loads

This commit is contained in:
nmzik
2026-09-25 20:07:21 +04:00
parent cf423df624
commit 1371219f5c
2 changed files with 35 additions and 37 deletions
+34 -35
View File
@@ -1007,17 +1007,12 @@ static RelocationInfo GetRelocationInfo(Elf64_Rela* r, Program* program) {
return ret;
}
static void RelocateRecord(uint32_t index, Elf64_Rela* r, Program* program, bool jmprela_table,
bool imports_only, std::vector<std::string>* unresolved) {
static bool RelocateRecord(uint32_t index, Elf64_Rela* r, Program* program, bool jmprela_table,
std::vector<std::string>* unresolved) {
KYTY_PROFILER_FUNCTION();
auto ri = GetRelocationInfo(r, program);
if (imports_only &&
(ri.bind_self || (ri.bind != BindType::Global && ri.bind != BindType::Weak))) {
return;
}
[[maybe_unused]] bool patched = false;
bool stubbed_import = false;
bool stubbed_func = false;
@@ -1098,17 +1093,23 @@ static void RelocateRecord(uint32_t index, Elf64_Rela* r, Program* program, bool
LOGF("Relocate: %s\n", dbg_str.c_str());
}
}
return ri.resolved;
}
static void RelocateRecords(Elf64_Rela* records, uint64_t size, Program* program,
bool jmprela_table, bool imports_only,
bool jmprela_table, uint32_t bit_base,
std::vector<std::string>* unresolved) {
KYTY_PROFILER_FUNCTION();
uint32_t index = 0;
for (auto* r = records;
reinterpret_cast<uint8_t*>(r) < reinterpret_cast<uint8_t*>(records) + size; r++, index++) {
RelocateRecord(index, r, program, jmprela_table, imports_only, unresolved);
const auto bit_index = bit_base + index;
if ((program->rela_bits[bit_index >> 3u] & (1u << (bit_index & 7u))) == 0) {
if (RelocateRecord(index, r, program, jmprela_table, unresolved)) {
program->rela_bits[bit_index >> 3u] |= 1u << (bit_index & 7u);
}
}
}
}
@@ -1314,8 +1315,6 @@ void RuntimeLinker::RelocateAll() {
for (auto* p: m_programs) {
Relocate(p);
}
m_relocated = true;
}
void RuntimeLinker::RelocateProgram(Program* program) {
@@ -1342,10 +1341,6 @@ void RuntimeLinker::UnloadProgram(Program* program) {
} else {
EXIT("program not found");
}
if (m_relocated) {
RelocateAll();
}
}
RuntimeLinker::RuntimeLinker(): m_symbols(std::make_unique<SymbolDatabase>()) {
@@ -1499,7 +1494,6 @@ void RuntimeLinker::Clear() {
g_tls_cached_main_tcb = nullptr;
g_desired_base_addr = SYSTEM_RESERVED + CODE_BASE_OFFSET;
m_symbols.reset();
m_relocated = false;
}
void RuntimeLinker::Resolve(const std::string& name, SymbolType type, Program* program,
@@ -2281,6 +2275,11 @@ void RuntimeLinker::ParseProgramDynamicInfo(Program* program) {
GetDynValue(elf, &program->dynamic_info->rela_table_total_size, DT_RELASZ);
GetDynValue(elf, &program->dynamic_info->rela_table_entry_size, DT_OS_RELAENT);
GetDynValue(elf, &program->dynamic_info->rela_table_entry_size, DT_RELAENT);
EXIT_NOT_IMPLEMENTED(program->dynamic_info->rela_table_total_size % sizeof(Elf64_Rela) != 0 ||
program->dynamic_info->jmprela_table_size % sizeof(Elf64_Rela) != 0);
const auto rela_count = program->dynamic_info->rela_table_total_size / sizeof(Elf64_Rela);
const auto jmprela_count = program->dynamic_info->jmprela_table_size / sizeof(Elf64_Rela);
program->rela_bits.resize((rela_count + jmprela_count + 7u) / 8u);
GetDynValue(elf, &program->dynamic_info->relative_count, DT_RELACOUNT);
@@ -2348,20 +2347,18 @@ static void InstallRelocateHandler(Program* program) {
}
// TODO(): check if this table already generated by compiler (sometimes it is missing)
if (program->custom_call_plt_vaddr == 0) {
program->custom_call_plt_num =
program->dynamic_info->jmprela_table_size / sizeof(Elf64_Rela);
auto size = Jit::CallPlt::GetSize(program->custom_call_plt_num);
program->custom_call_plt_vaddr = Libs::LibKernel::Memory::AllocateRuntimeMemory(
SYSTEM_RESERVED, size, Common::VirtualMemory::Mode::Write, "custom_call_plt");
EXIT_NOT_IMPLEMENTED(program->custom_call_plt_vaddr == 0);
auto* code = new (reinterpret_cast<void*>(program->custom_call_plt_vaddr))
Jit::CallPlt(program->custom_call_plt_num);
code->SetPltGot(pltgot_vaddr);
EXIT_IF(!Libs::LibKernel::Memory::ProtectGuestMemory(program->custom_call_plt_vaddr, size,
Common::VirtualMemory::Mode::Execute));
Common::VirtualMemory::FlushInstructionCache(program->custom_call_plt_vaddr, size);
}
program->custom_call_plt_num =
program->dynamic_info->jmprela_table_size / sizeof(Elf64_Rela);
auto size = Jit::CallPlt::GetSize(program->custom_call_plt_num);
program->custom_call_plt_vaddr = Libs::LibKernel::Memory::AllocateRuntimeMemory(
SYSTEM_RESERVED, size, Common::VirtualMemory::Mode::Write, "custom_call_plt");
EXIT_NOT_IMPLEMENTED(program->custom_call_plt_vaddr == 0);
auto* code = new (reinterpret_cast<void*>(program->custom_call_plt_vaddr))
Jit::CallPlt(program->custom_call_plt_num);
code->SetPltGot(pltgot_vaddr);
EXIT_IF(!Libs::LibKernel::Memory::ProtectGuestMemory(program->custom_call_plt_vaddr, size,
Common::VirtualMemory::Mode::Execute));
Common::VirtualMemory::FlushInstructionCache(program->custom_call_plt_vaddr, size);
}
void RuntimeLinker::Relocate(Program* program) {
@@ -2385,16 +2382,18 @@ void RuntimeLinker::Relocate(Program* program) {
EXIT_NOT_IMPLEMENTED(program->dynamic_info->symbol_table == nullptr);
EXIT_NOT_IMPLEMENTED(program->dynamic_info->pltgot_vaddr == 0);
InstallRelocateHandler(program);
if (program->custom_call_plt_vaddr == 0) {
InstallRelocateHandler(program);
}
std::vector<std::string> unresolved;
const bool imports_only = program->relocated;
const auto rela_count = static_cast<uint32_t>(
program->dynamic_info->rela_table_total_size / sizeof(Elf64_Rela));
RelocateRecords(program->dynamic_info->rela_table, program->dynamic_info->rela_table_total_size,
program, false, imports_only, &unresolved);
program, false, 0, &unresolved);
RelocateRecords(program->dynamic_info->jmprela_table, program->dynamic_info->jmprela_table_size,
program, true, imports_only, &unresolved);
program->relocated = true;
program, true, rela_count, &unresolved);
if (program->tls.image_vaddr != 0 && program->tls.init_size != 0 &&
program->tls.init_image.empty()) {
+1 -2
View File
@@ -132,7 +132,7 @@ struct Program {
ThreadLocalStorage tls;
bool fail_if_global_not_resolved = true;
bool dbg_print_reloc = false;
bool relocated = false;
std::vector<uint8_t> rela_bits;
uint64_t proc_param_vaddr = 0;
uint64_t custom_call_plt_vaddr = 0;
uint32_t custom_call_plt_num = 0;
@@ -201,7 +201,6 @@ private:
std::vector<Program*> m_programs;
std::unique_ptr<SymbolDatabase> m_symbols;
bool m_relocated = false;
Common::Mutex m_mutex;
application_heap_malloc_func_t m_application_heap_malloc = nullptr;