2024-02-23 21:32:32 +00:00
|
|
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
|
2023-11-05 11:22:18 +00:00
|
|
|
#include <Zydis/Zydis.h>
|
2024-03-26 10:31:46 +00:00
|
|
|
#include <common/assert.h>
|
2024-03-11 11:26:33 +00:00
|
|
|
#include "common/config.h"
|
2024-02-27 22:10:34 +00:00
|
|
|
#include "common/logging/log.h"
|
2024-03-11 11:26:33 +00:00
|
|
|
#include "common/path_util.h"
|
2023-11-05 11:41:10 +00:00
|
|
|
#include "common/string_util.h"
|
2023-11-05 23:11:54 +00:00
|
|
|
#include "core/aerolib/aerolib.h"
|
|
|
|
#include "core/aerolib/stubs.h"
|
2024-04-13 21:35:48 +00:00
|
|
|
#include "core/libraries/kernel/thread_management.h"
|
2023-11-05 23:11:54 +00:00
|
|
|
#include "core/linker.h"
|
2024-02-27 22:10:34 +00:00
|
|
|
#include "core/tls.h"
|
2023-11-05 23:11:54 +00:00
|
|
|
#include "core/virtual_memory.h"
|
|
|
|
|
|
|
|
namespace Core {
|
2023-05-25 10:16:53 +00:00
|
|
|
|
2024-03-26 16:29:37 +00:00
|
|
|
static u64 LoadAddress = SYSTEM_RESERVED + CODE_BASE_OFFSET;
|
|
|
|
static constexpr u64 CODE_BASE_INCR = 0x010000000u;
|
2023-05-25 10:16:53 +00:00
|
|
|
|
2024-02-27 22:10:34 +00:00
|
|
|
static u64 GetAlignedSize(const elf_program_header& phdr) {
|
2024-02-23 20:57:57 +00:00
|
|
|
return (phdr.p_align != 0 ? (phdr.p_memsz + (phdr.p_align - 1)) & ~(phdr.p_align - 1)
|
|
|
|
: phdr.p_memsz);
|
2023-05-23 16:39:24 +00:00
|
|
|
}
|
|
|
|
|
2024-02-27 22:10:34 +00:00
|
|
|
static u64 CalculateBaseSize(const elf_header& ehdr, std::span<const elf_program_header> phdr) {
|
2023-10-26 20:07:15 +00:00
|
|
|
u64 base_size = 0;
|
2024-02-23 20:57:57 +00:00
|
|
|
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)) {
|
2024-02-27 22:10:34 +00:00
|
|
|
u64 last_addr = phdr[i].p_vaddr + GetAlignedSize(phdr[i]);
|
2024-02-23 20:57:57 +00:00
|
|
|
if (last_addr > base_size) {
|
2023-10-26 20:07:15 +00:00
|
|
|
base_size = last_addr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return base_size;
|
2023-05-23 16:39:24 +00:00
|
|
|
}
|
|
|
|
|
2024-02-27 22:10:34 +00:00
|
|
|
static std::string EncodeId(u64 nVal) {
|
2023-10-26 20:07:15 +00:00
|
|
|
std::string enc;
|
|
|
|
const char pCodes[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-";
|
2024-02-23 20:57:57 +00:00
|
|
|
if (nVal < 0x40u) {
|
2023-10-26 20:07:15 +00:00
|
|
|
enc += pCodes[nVal];
|
2024-02-23 20:57:57 +00:00
|
|
|
} else {
|
|
|
|
if (nVal < 0x1000u) {
|
2023-10-26 20:07:15 +00:00
|
|
|
enc += pCodes[static_cast<u16>(nVal >> 6u) & 0x3fu];
|
|
|
|
enc += pCodes[nVal & 0x3fu];
|
2024-02-23 20:57:57 +00:00
|
|
|
} else {
|
2023-10-26 20:07:15 +00:00
|
|
|
enc += pCodes[static_cast<u16>(nVal >> 12u) & 0x3fu];
|
|
|
|
enc += pCodes[static_cast<u16>(nVal >> 6u) & 0x3fu];
|
|
|
|
enc += pCodes[nVal & 0x3fu];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return enc;
|
2023-06-14 04:47:44 +00:00
|
|
|
}
|
2023-10-26 20:07:15 +00:00
|
|
|
|
|
|
|
Linker::Linker() = default;
|
|
|
|
|
|
|
|
Linker::~Linker() = default;
|
|
|
|
|
2024-02-27 22:10:34 +00:00
|
|
|
Module* Linker::LoadModule(const std::filesystem::path& elf_name) {
|
2023-10-22 14:10:25 +00:00
|
|
|
std::scoped_lock lock{m_mutex};
|
2023-05-25 10:16:53 +00:00
|
|
|
|
2024-02-27 22:10:34 +00:00
|
|
|
if (!std::filesystem::exists(elf_name)) {
|
|
|
|
LOG_ERROR(Core_Linker, "Provided module {} does not exist", elf_name.string());
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2023-10-26 20:07:15 +00:00
|
|
|
auto& m = m_modules.emplace_back();
|
2024-02-27 22:10:34 +00:00
|
|
|
m = std::make_unique<Module>();
|
|
|
|
m->elf.Open(elf_name);
|
2024-03-11 11:26:33 +00:00
|
|
|
m->file_name = std::filesystem::path(elf_name).filename().string();
|
2024-02-27 22:10:34 +00:00
|
|
|
|
|
|
|
if (m->elf.IsElfFile()) {
|
|
|
|
LoadModuleToMemory(m.get());
|
|
|
|
LoadDynamicInfo(m.get());
|
|
|
|
LoadSymbols(m.get());
|
2023-10-26 20:07:15 +00:00
|
|
|
} else {
|
|
|
|
m_modules.pop_back();
|
|
|
|
return nullptr; // It is not a valid elf file //TODO check it why!
|
|
|
|
}
|
2023-05-23 04:48:25 +00:00
|
|
|
|
2024-02-27 22:10:34 +00:00
|
|
|
return m.get();
|
2023-05-23 07:47:56 +00:00
|
|
|
}
|
|
|
|
|
2024-01-20 12:29:23 +00:00
|
|
|
void Linker::LoadModuleToMemory(Module* m) {
|
2024-02-23 20:57:57 +00:00
|
|
|
// get elf header, program header
|
2023-10-26 19:55:13 +00:00
|
|
|
const auto elf_header = m->elf.GetElfHeader();
|
|
|
|
const auto elf_pheader = m->elf.GetProgramHeader();
|
2023-05-23 16:39:24 +00:00
|
|
|
|
2024-02-27 22:10:34 +00:00
|
|
|
u64 base_size = CalculateBaseSize(elf_header, elf_pheader);
|
2024-02-23 20:57:57 +00:00
|
|
|
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?
|
|
|
|
|
2024-02-27 22:10:34 +00:00
|
|
|
m->base_virtual_addr = VirtualMemory::memory_alloc(LoadAddress, m->aligned_base_size,
|
2024-02-23 20:57:57 +00:00
|
|
|
VirtualMemory::MemoryMode::ExecuteReadWrite);
|
|
|
|
|
2024-03-26 16:29:37 +00:00
|
|
|
LoadAddress += CODE_BASE_INCR * (1 + m->aligned_base_size / CODE_BASE_INCR);
|
|
|
|
|
2024-02-27 22:10:34 +00:00
|
|
|
LOG_INFO(Core_Linker, "====Load Module to Memory ========");
|
|
|
|
LOG_INFO(Core_Linker, "base_virtual_addr ......: {:#018x}", m->base_virtual_addr);
|
|
|
|
LOG_INFO(Core_Linker, "base_size ..............: {:#018x}", base_size);
|
|
|
|
LOG_INFO(Core_Linker, "aligned_base_size ......: {:#018x}", m->aligned_base_size);
|
2024-02-23 20:57:57 +00:00
|
|
|
|
|
|
|
for (u16 i = 0; i < elf_header.e_phnum; i++) {
|
|
|
|
switch (elf_pheader[i].p_type) {
|
|
|
|
case PT_LOAD:
|
|
|
|
case PT_SCE_RELRO:
|
|
|
|
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;
|
2024-02-27 22:10:34 +00:00
|
|
|
u64 segment_memory_size = GetAlignedSize(elf_pheader[i]);
|
2024-02-23 20:57:57 +00:00
|
|
|
auto segment_mode = m->elf.ElfPheaderFlagsStr(elf_pheader[i].p_flags);
|
2024-02-27 22:10:34 +00:00
|
|
|
LOG_INFO(Core_Linker, "program header = [{}] type = {}", i,
|
|
|
|
m->elf.ElfPheaderTypeStr(elf_pheader[i].p_type));
|
|
|
|
LOG_INFO(Core_Linker, "segment_addr ..........: {:#018x}", segment_addr);
|
|
|
|
LOG_INFO(Core_Linker, "segment_file_size .....: {}", segment_file_size);
|
|
|
|
LOG_INFO(Core_Linker, "segment_memory_size ...: {}", segment_memory_size);
|
|
|
|
LOG_INFO(Core_Linker, "segment_mode ..........: {}", segment_mode);
|
2024-02-23 20:57:57 +00:00
|
|
|
|
|
|
|
m->elf.LoadSegment(segment_addr, elf_pheader[i].p_offset, segment_file_size);
|
|
|
|
|
|
|
|
if (elf_pheader[i].p_flags & PF_EXEC) {
|
|
|
|
PatchTLS(segment_addr, segment_file_size);
|
|
|
|
}
|
|
|
|
} else {
|
2024-02-27 22:10:34 +00:00
|
|
|
LOG_ERROR(Core_Linker, "p_memsz==0 in type {}",
|
|
|
|
m->elf.ElfPheaderTypeStr(elf_pheader[i].p_type));
|
2024-02-23 20:57:57 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case PT_DYNAMIC:
|
|
|
|
if (elf_pheader[i].p_filesz != 0) {
|
|
|
|
m->m_dynamic.resize(elf_pheader[i].p_filesz);
|
|
|
|
m->elf.LoadSegment(reinterpret_cast<u64>(m->m_dynamic.data()),
|
|
|
|
elf_pheader[i].p_offset, elf_pheader[i].p_filesz);
|
|
|
|
} else {
|
2024-02-27 22:10:34 +00:00
|
|
|
LOG_ERROR(Core_Linker, "p_filesz==0 in type {}",
|
|
|
|
m->elf.ElfPheaderTypeStr(elf_pheader[i].p_type));
|
2024-02-23 20:57:57 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case PT_SCE_DYNLIBDATA:
|
|
|
|
if (elf_pheader[i].p_filesz != 0) {
|
|
|
|
m->m_dynamic_data.resize(elf_pheader[i].p_filesz);
|
|
|
|
m->elf.LoadSegment(reinterpret_cast<u64>(m->m_dynamic_data.data()),
|
|
|
|
elf_pheader[i].p_offset, elf_pheader[i].p_filesz);
|
|
|
|
} else {
|
2024-02-27 22:10:34 +00:00
|
|
|
LOG_ERROR(Core_Linker, "p_filesz==0 in type {}",
|
|
|
|
m->elf.ElfPheaderTypeStr(elf_pheader[i].p_type));
|
2024-02-23 20:57:57 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case PT_TLS:
|
|
|
|
m->tls.image_virtual_addr = elf_pheader[i].p_vaddr + m->base_virtual_addr;
|
2024-02-27 22:10:34 +00:00
|
|
|
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);
|
2024-02-23 20:57:57 +00:00
|
|
|
break;
|
2024-03-26 16:48:26 +00:00
|
|
|
case PT_SCE_PROCPARAM:
|
|
|
|
m->proc_param_virtual_addr = elf_pheader[i].p_vaddr + m->base_virtual_addr;
|
|
|
|
break;
|
2024-02-23 20:57:57 +00:00
|
|
|
default:
|
2024-02-27 22:10:34 +00:00
|
|
|
LOG_ERROR(Core_Linker, "Unimplemented type {}",
|
|
|
|
m->elf.ElfPheaderTypeStr(elf_pheader[i].p_type));
|
2024-02-23 20:57:57 +00:00
|
|
|
}
|
|
|
|
}
|
2024-02-27 22:10:34 +00:00
|
|
|
LOG_INFO(Core_Linker, "program entry addr ..........: {:#018x}",
|
|
|
|
m->elf.GetElfEntry() + m->base_virtual_addr);
|
2023-06-08 09:51:11 +00:00
|
|
|
}
|
|
|
|
|
2024-02-23 20:57:57 +00:00
|
|
|
void Linker::LoadDynamicInfo(Module* m) {
|
|
|
|
for (const auto* dyn = reinterpret_cast<elf_dynamic*>(m->m_dynamic.data());
|
|
|
|
dyn->d_tag != DT_NULL; dyn++) {
|
|
|
|
switch (dyn->d_tag) {
|
|
|
|
case DT_SCE_HASH: // Offset of the hash table.
|
|
|
|
m->dynamic_info.hash_table =
|
|
|
|
reinterpret_cast<void*>(m->m_dynamic_data.data() + dyn->d_un.d_ptr);
|
|
|
|
break;
|
|
|
|
case DT_SCE_HASHSZ: // Size of the hash table
|
2023-10-26 20:07:15 +00:00
|
|
|
m->dynamic_info.hash_table_size = dyn->d_un.d_val;
|
2024-02-23 20:57:57 +00:00
|
|
|
break;
|
|
|
|
case DT_SCE_STRTAB: // Offset of the string table.
|
|
|
|
m->dynamic_info.str_table =
|
|
|
|
reinterpret_cast<char*>(m->m_dynamic_data.data() + dyn->d_un.d_ptr);
|
|
|
|
break;
|
|
|
|
case DT_SCE_STRSZ: // Size of the string table.
|
2023-10-26 20:07:15 +00:00
|
|
|
m->dynamic_info.str_table_size = dyn->d_un.d_val;
|
2024-02-23 20:57:57 +00:00
|
|
|
break;
|
|
|
|
case DT_SCE_SYMTAB: // Offset of the symbol table.
|
|
|
|
m->dynamic_info.symbol_table =
|
|
|
|
reinterpret_cast<elf_symbol*>(m->m_dynamic_data.data() + dyn->d_un.d_ptr);
|
|
|
|
break;
|
|
|
|
case DT_SCE_SYMTABSZ: // Size of the symbol table.
|
2023-10-26 20:07:15 +00:00
|
|
|
m->dynamic_info.symbol_table_total_size = dyn->d_un.d_val;
|
2024-02-23 20:57:57 +00:00
|
|
|
break;
|
|
|
|
case DT_INIT:
|
2023-10-26 20:07:15 +00:00
|
|
|
m->dynamic_info.init_virtual_addr = dyn->d_un.d_ptr;
|
2024-02-23 20:57:57 +00:00
|
|
|
break;
|
|
|
|
case DT_FINI:
|
2023-10-26 20:07:15 +00:00
|
|
|
m->dynamic_info.fini_virtual_addr = dyn->d_un.d_ptr;
|
2024-02-23 20:57:57 +00:00
|
|
|
break;
|
|
|
|
case DT_SCE_PLTGOT: // Offset of the global offset table.
|
2023-10-26 20:07:15 +00:00
|
|
|
m->dynamic_info.pltgot_virtual_addr = dyn->d_un.d_ptr;
|
2024-02-23 20:57:57 +00:00
|
|
|
break;
|
|
|
|
case DT_SCE_JMPREL: // Offset of the table containing jump slots.
|
|
|
|
m->dynamic_info.jmp_relocation_table =
|
|
|
|
reinterpret_cast<elf_relocation*>(m->m_dynamic_data.data() + dyn->d_un.d_ptr);
|
|
|
|
break;
|
|
|
|
case DT_SCE_PLTRELSZ: // Size of the global offset table.
|
2023-10-26 20:07:15 +00:00
|
|
|
m->dynamic_info.jmp_relocation_table_size = dyn->d_un.d_val;
|
2024-02-23 20:57:57 +00:00
|
|
|
break;
|
|
|
|
case DT_SCE_PLTREL: // The type of relocations in the relocation table. Should be DT_RELA
|
2023-10-26 20:07:15 +00:00
|
|
|
m->dynamic_info.jmp_relocation_type = dyn->d_un.d_val;
|
2024-02-23 20:57:57 +00:00
|
|
|
if (m->dynamic_info.jmp_relocation_type != DT_RELA) {
|
2024-02-27 22:10:34 +00:00
|
|
|
LOG_WARNING(Core_Linker, "DT_SCE_PLTREL is NOT DT_RELA should check!");
|
2024-02-23 20:57:57 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case DT_SCE_RELA: // Offset of the relocation table.
|
|
|
|
m->dynamic_info.relocation_table =
|
|
|
|
reinterpret_cast<elf_relocation*>(m->m_dynamic_data.data() + dyn->d_un.d_ptr);
|
|
|
|
break;
|
|
|
|
case DT_SCE_RELASZ: // Size of the relocation table.
|
2023-10-26 20:07:15 +00:00
|
|
|
m->dynamic_info.relocation_table_size = dyn->d_un.d_val;
|
2024-02-23 20:57:57 +00:00
|
|
|
break;
|
|
|
|
case DT_SCE_RELAENT: // The size of relocation table entries.
|
2023-10-26 20:07:15 +00:00
|
|
|
m->dynamic_info.relocation_table_entries_size = dyn->d_un.d_val;
|
2024-02-23 20:57:57 +00:00
|
|
|
if (m->dynamic_info.relocation_table_entries_size !=
|
|
|
|
0x18) // this value should always be 0x18
|
|
|
|
{
|
2024-02-27 22:10:34 +00:00
|
|
|
LOG_WARNING(Core_Linker, "DT_SCE_RELAENT is NOT 0x18 should check!");
|
2024-02-23 20:57:57 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case DT_INIT_ARRAY: // Address of the array of pointers to initialization functions
|
2023-10-26 20:07:15 +00:00
|
|
|
m->dynamic_info.init_array_virtual_addr = dyn->d_un.d_ptr;
|
2024-02-23 20:57:57 +00:00
|
|
|
break;
|
|
|
|
case DT_FINI_ARRAY: // Address of the array of pointers to termination functions
|
2023-10-26 20:07:15 +00:00
|
|
|
m->dynamic_info.fini_array_virtual_addr = dyn->d_un.d_ptr;
|
2024-02-23 20:57:57 +00:00
|
|
|
break;
|
|
|
|
case DT_INIT_ARRAYSZ: // Size in bytes of the array of initialization functions
|
2023-10-26 20:07:15 +00:00
|
|
|
m->dynamic_info.init_array_size = dyn->d_un.d_val;
|
2024-02-23 20:57:57 +00:00
|
|
|
break;
|
|
|
|
case DT_FINI_ARRAYSZ: // Size in bytes of the array of terminationfunctions
|
2023-10-26 20:07:15 +00:00
|
|
|
m->dynamic_info.fini_array_size = dyn->d_un.d_val;
|
2024-02-23 20:57:57 +00:00
|
|
|
break;
|
|
|
|
case DT_PREINIT_ARRAY: // Address of the array of pointers to pre - initialization functions
|
2023-10-26 20:07:15 +00:00
|
|
|
m->dynamic_info.preinit_array_virtual_addr = dyn->d_un.d_ptr;
|
2024-02-23 20:57:57 +00:00
|
|
|
break;
|
|
|
|
case DT_PREINIT_ARRAYSZ: // Size in bytes of the array of pre - initialization functions
|
2023-10-26 20:07:15 +00:00
|
|
|
m->dynamic_info.preinit_array_size = dyn->d_un.d_val;
|
2024-02-23 20:57:57 +00:00
|
|
|
break;
|
|
|
|
case DT_SCE_SYMENT: // The size of symbol table entries
|
2023-10-26 20:07:15 +00:00
|
|
|
m->dynamic_info.symbol_table_entries_size = dyn->d_un.d_val;
|
2024-02-23 20:57:57 +00:00
|
|
|
if (m->dynamic_info.symbol_table_entries_size !=
|
|
|
|
0x18) // this value should always be 0x18
|
|
|
|
{
|
2024-02-27 22:10:34 +00:00
|
|
|
LOG_WARNING(Core_Linker, "DT_SCE_SYMENT is NOT 0x18 should check!");
|
2024-02-23 20:57:57 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case DT_DEBUG:
|
2023-10-26 20:07:15 +00:00
|
|
|
m->dynamic_info.debug = dyn->d_un.d_val;
|
2024-02-23 20:57:57 +00:00
|
|
|
break;
|
|
|
|
case DT_TEXTREL:
|
2023-10-26 20:07:15 +00:00
|
|
|
m->dynamic_info.textrel = dyn->d_un.d_val;
|
2024-02-23 20:57:57 +00:00
|
|
|
break;
|
|
|
|
case DT_FLAGS:
|
2023-10-26 20:07:15 +00:00
|
|
|
m->dynamic_info.flags = dyn->d_un.d_val;
|
2024-02-23 20:57:57 +00:00
|
|
|
if (m->dynamic_info.flags != 0x04) // this value should always be DF_TEXTREL (0x04)
|
|
|
|
{
|
2024-02-27 22:10:34 +00:00
|
|
|
LOG_WARNING(Core_Linker, "DT_FLAGS is NOT 0x04 should check!");
|
2024-02-23 20:57:57 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case DT_NEEDED: // Offset of the library string in the string table to be linked in.
|
|
|
|
if (m->dynamic_info.str_table !=
|
|
|
|
nullptr) // in theory this should already be filled from about just make a test case
|
|
|
|
{
|
2023-10-26 20:07:15 +00:00
|
|
|
m->dynamic_info.needed.push_back(m->dynamic_info.str_table + dyn->d_un.d_val);
|
2024-02-23 20:57:57 +00:00
|
|
|
} else {
|
2024-02-27 22:10:34 +00:00
|
|
|
LOG_ERROR(Core_Linker, "DT_NEEDED str table is not loaded should check!");
|
2024-02-23 20:57:57 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case DT_SCE_NEEDED_MODULE: {
|
|
|
|
ModuleInfo info{};
|
|
|
|
info.value = dyn->d_un.d_val;
|
|
|
|
info.name = m->dynamic_info.str_table + info.name_offset;
|
2024-02-27 22:10:34 +00:00
|
|
|
info.enc_id = EncodeId(info.id);
|
2024-02-23 20:57:57 +00:00
|
|
|
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;
|
2024-02-27 22:10:34 +00:00
|
|
|
info.enc_id = EncodeId(info.id);
|
2024-02-23 20:57:57 +00:00
|
|
|
m->dynamic_info.import_libs.push_back(info);
|
|
|
|
} break;
|
|
|
|
case DT_SCE_FINGERPRINT:
|
|
|
|
// The fingerprint is a 24 byte (0x18) size buffer that contains a unique identifier for
|
|
|
|
// the given app. How exactly this is generated isn't known, however it is not necessary
|
|
|
|
// to have a valid fingerprint. While an invalid fingerprint will cause a warning to be
|
|
|
|
// printed to the kernel log, the ELF will still load and run.
|
2024-02-27 22:10:34 +00:00
|
|
|
LOG_INFO(Core_Linker, "unsupported DT_SCE_FINGERPRINT value = ..........: {:#018x}",
|
|
|
|
dyn->d_un.d_val);
|
2024-02-23 20:57:57 +00:00
|
|
|
break;
|
|
|
|
case DT_SCE_IMPORT_LIB_ATTR:
|
|
|
|
// The upper 32-bits should contain the module index multiplied by 0x10000. The lower
|
|
|
|
// 32-bits should be a constant 0x9.
|
2024-02-27 22:10:34 +00:00
|
|
|
LOG_INFO(Core_Linker, "unsupported DT_SCE_IMPORT_LIB_ATTR value = ......: {:#018x}",
|
|
|
|
dyn->d_un.d_val);
|
2024-02-23 20:57:57 +00:00
|
|
|
break;
|
|
|
|
case DT_SCE_ORIGINAL_FILENAME:
|
2023-10-26 20:07:15 +00:00
|
|
|
m->dynamic_info.filename = m->dynamic_info.str_table + dyn->d_un.d_val;
|
2024-02-23 20:57:57 +00:00
|
|
|
break;
|
|
|
|
case DT_SCE_MODULE_INFO: // probably only useable in shared modules
|
|
|
|
{
|
|
|
|
ModuleInfo info{};
|
|
|
|
info.value = dyn->d_un.d_val;
|
|
|
|
info.name = m->dynamic_info.str_table + info.name_offset;
|
2024-02-27 22:10:34 +00:00
|
|
|
info.enc_id = EncodeId(info.id);
|
2024-02-23 20:57:57 +00:00
|
|
|
m->dynamic_info.export_modules.push_back(info);
|
|
|
|
} break;
|
|
|
|
case DT_SCE_MODULE_ATTR:
|
|
|
|
// TODO?
|
2024-02-27 22:10:34 +00:00
|
|
|
LOG_INFO(Core_Linker, "unsupported DT_SCE_MODULE_ATTR value = ..........: {:#018x}",
|
|
|
|
dyn->d_un.d_val);
|
2024-02-23 20:57:57 +00:00
|
|
|
break;
|
|
|
|
case DT_SCE_EXPORT_LIB: {
|
|
|
|
LibraryInfo info{};
|
|
|
|
info.value = dyn->d_un.d_val;
|
|
|
|
info.name = m->dynamic_info.str_table + info.name_offset;
|
2024-02-27 22:10:34 +00:00
|
|
|
info.enc_id = EncodeId(info.id);
|
2024-02-23 20:57:57 +00:00
|
|
|
m->dynamic_info.export_libs.push_back(info);
|
|
|
|
} break;
|
|
|
|
default:
|
2024-02-27 22:10:34 +00:00
|
|
|
LOG_INFO(Core_Linker, "unsupported dynamic tag ..........: {:#018x}", dyn->d_tag);
|
2024-02-23 20:57:57 +00:00
|
|
|
}
|
|
|
|
}
|
2023-06-13 04:43:58 +00:00
|
|
|
}
|
|
|
|
|
2024-02-23 20:57:57 +00:00
|
|
|
const ModuleInfo* Linker::FindModule(const Module& m, const std::string& id) {
|
2023-10-26 20:07:15 +00:00
|
|
|
const auto& import_modules = m.dynamic_info.import_modules;
|
2024-02-23 20:57:57 +00:00
|
|
|
int index = 0;
|
|
|
|
for (const auto& mod : import_modules) {
|
|
|
|
if (mod.enc_id.compare(id) == 0) {
|
|
|
|
return &import_modules.at(index);
|
|
|
|
}
|
|
|
|
index++;
|
|
|
|
}
|
2023-10-26 20:07:15 +00:00
|
|
|
const auto& export_modules = m.dynamic_info.export_modules;
|
2024-02-23 20:57:57 +00:00
|
|
|
index = 0;
|
|
|
|
for (const auto& mod : export_modules) {
|
|
|
|
if (mod.enc_id.compare(id) == 0) {
|
|
|
|
return &export_modules.at(index);
|
|
|
|
}
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
return nullptr;
|
2023-06-18 14:54:22 +00:00
|
|
|
}
|
|
|
|
|
2024-02-23 20:57:57 +00:00
|
|
|
const LibraryInfo* Linker::FindLibrary(const Module& m, const std::string& id) {
|
2023-10-26 20:07:15 +00:00
|
|
|
const auto& import_libs = m.dynamic_info.import_libs;
|
2024-02-23 20:57:57 +00:00
|
|
|
int index = 0;
|
|
|
|
for (const auto& lib : import_libs) {
|
|
|
|
if (lib.enc_id.compare(id) == 0) {
|
|
|
|
return &import_libs.at(index);
|
|
|
|
}
|
|
|
|
index++;
|
|
|
|
}
|
2023-10-26 20:07:15 +00:00
|
|
|
const auto& export_libs = m.dynamic_info.export_libs;
|
2024-02-23 20:57:57 +00:00
|
|
|
index = 0;
|
|
|
|
for (const auto& lib : export_libs) {
|
|
|
|
if (lib.enc_id.compare(id) == 0) {
|
|
|
|
return &export_libs.at(index);
|
|
|
|
}
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
return nullptr;
|
2023-06-18 14:54:22 +00:00
|
|
|
}
|
|
|
|
|
2024-02-23 20:57:57 +00:00
|
|
|
void Linker::LoadSymbols(Module* m) {
|
2023-06-26 15:12:19 +00:00
|
|
|
|
2024-03-26 12:05:18 +00:00
|
|
|
const auto symbol_database = [this](Module* m, Loader::SymbolsResolver* symbol,
|
|
|
|
bool export_func) {
|
|
|
|
if (m->dynamic_info.symbol_table == nullptr || m->dynamic_info.str_table == nullptr ||
|
|
|
|
m->dynamic_info.symbol_table_total_size == 0) {
|
|
|
|
LOG_INFO(Core_Linker, "Symbol table not found!");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (auto* sym = m->dynamic_info.symbol_table;
|
|
|
|
reinterpret_cast<u8*>(sym) < reinterpret_cast<u8*>(m->dynamic_info.symbol_table) +
|
|
|
|
m->dynamic_info.symbol_table_total_size;
|
|
|
|
sym++) {
|
|
|
|
std::string id = std::string(m->dynamic_info.str_table + sym->st_name);
|
2024-02-23 20:57:57 +00:00
|
|
|
auto bind = sym->GetBind();
|
|
|
|
auto type = sym->GetType();
|
|
|
|
auto visibility = sym->GetVisibility();
|
2024-03-26 12:05:18 +00:00
|
|
|
const auto ids = Common::SplitString(id, '#');
|
|
|
|
if (ids.size() == 3) {
|
|
|
|
const auto* library = FindLibrary(*m, ids.at(1));
|
|
|
|
const auto* module = FindModule(*m, ids.at(2));
|
|
|
|
ASSERT_MSG(library && module, "Unable to find library and module");
|
|
|
|
if ((bind == STB_GLOBAL || bind == STB_WEAK) &&
|
|
|
|
(type == STT_FUN || type == STT_OBJECT) &&
|
|
|
|
export_func == (sym->st_value != 0)) {
|
|
|
|
std::string nidName = "";
|
|
|
|
auto aeronid = AeroLib::FindByNid(ids.at(0).c_str());
|
|
|
|
if (aeronid != nullptr) {
|
|
|
|
nidName = aeronid->name;
|
|
|
|
} else {
|
|
|
|
nidName = "UNK";
|
|
|
|
}
|
|
|
|
Loader::SymbolResolver sym_r{};
|
|
|
|
sym_r.name = ids.at(0);
|
|
|
|
sym_r.nidName = nidName;
|
|
|
|
sym_r.library = library->name;
|
|
|
|
sym_r.library_version = library->version;
|
|
|
|
sym_r.module = module->name;
|
|
|
|
sym_r.module_version_major = module->version_major;
|
|
|
|
sym_r.module_version_minor = module->version_minor;
|
|
|
|
switch (type) {
|
|
|
|
case STT_NOTYPE:
|
|
|
|
sym_r.type = Loader::SymbolType::NoType;
|
|
|
|
break;
|
|
|
|
case STT_FUN:
|
|
|
|
sym_r.type = Loader::SymbolType::Function;
|
|
|
|
break;
|
|
|
|
case STT_OBJECT:
|
|
|
|
sym_r.type = Loader::SymbolType::Object;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
sym_r.type = Loader::SymbolType::Unknown;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
symbol->AddSymbol(sym_r,
|
2024-03-26 15:17:59 +00:00
|
|
|
(export_func ? sym->st_value + m->base_virtual_addr : 0));
|
2024-03-11 11:26:33 +00:00
|
|
|
}
|
2024-02-23 20:57:57 +00:00
|
|
|
}
|
|
|
|
}
|
2024-03-26 12:05:18 +00:00
|
|
|
};
|
|
|
|
symbol_database(m, &m->export_sym, true);
|
|
|
|
symbol_database(m, &m->import_sym, false);
|
2023-07-04 15:34:23 +00:00
|
|
|
}
|
2024-02-27 22:10:34 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
auto* symbolsTlb = m->dynamic_info.symbol_table;
|
|
|
|
auto* namesTlb = m->dynamic_info.str_table;
|
|
|
|
|
|
|
|
u64 rel_value = 0;
|
|
|
|
u64 rel_base_virtual_addr = m->base_virtual_addr;
|
|
|
|
u64 rel_virtual_addr = m->base_virtual_addr + rel->rel_offset;
|
|
|
|
bool rel_isResolved = false;
|
2024-03-11 11:26:33 +00:00
|
|
|
Loader::SymbolType rel_sym_type = Loader::SymbolType::Unknown;
|
2024-02-27 22:10:34 +00:00
|
|
|
std::string rel_name;
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case R_X86_64_RELATIVE:
|
|
|
|
rel_value = rel_base_virtual_addr + addend;
|
|
|
|
rel_isResolved = true;
|
2023-07-11 15:50:29 +00:00
|
|
|
break;
|
2024-03-26 15:17:59 +00:00
|
|
|
case R_X86_64_DTPMOD64:
|
|
|
|
rel_value = reinterpret_cast<uint64_t>(m);
|
|
|
|
rel_isResolved = true;
|
|
|
|
rel_sym_type = Loader::SymbolType::Tls;
|
|
|
|
break;
|
|
|
|
case R_X86_64_GLOB_DAT:
|
|
|
|
case R_X86_64_JUMP_SLOT:
|
|
|
|
addend = 0;
|
|
|
|
case R_X86_64_64: {
|
2024-02-27 22:10:34 +00:00
|
|
|
auto sym = symbolsTlb[symbol];
|
|
|
|
auto sym_bind = sym.GetBind();
|
|
|
|
auto sym_type = sym.GetType();
|
|
|
|
auto sym_visibility = sym.GetVisibility();
|
|
|
|
u64 symbol_vitrual_addr = 0;
|
|
|
|
Loader::SymbolRecord symrec{};
|
|
|
|
switch (sym_type) {
|
|
|
|
case STT_FUN:
|
2024-03-11 11:26:33 +00:00
|
|
|
rel_sym_type = Loader::SymbolType::Function;
|
2024-02-27 22:10:34 +00:00
|
|
|
break;
|
|
|
|
case STT_OBJECT:
|
2024-03-11 11:26:33 +00:00
|
|
|
rel_sym_type = Loader::SymbolType::Object;
|
2024-02-27 22:10:34 +00:00
|
|
|
break;
|
2024-03-26 15:17:59 +00:00
|
|
|
case STT_NOTYPE:
|
|
|
|
rel_sym_type = Loader::SymbolType::NoType;
|
|
|
|
break;
|
2024-02-27 22:10:34 +00:00
|
|
|
default:
|
2024-03-26 15:17:59 +00:00
|
|
|
ASSERT_MSG(0, "unknown symbol type {}", sym_type);
|
2024-02-27 22:10:34 +00:00
|
|
|
}
|
|
|
|
if (sym_visibility != 0) // should be zero log if else
|
|
|
|
{
|
|
|
|
LOG_INFO(Core_Linker, "symbol visilibity !=0");
|
2023-07-11 15:50:29 +00:00
|
|
|
}
|
2024-02-27 22:10:34 +00:00
|
|
|
switch (sym_bind) {
|
2024-03-26 15:17:59 +00:00
|
|
|
case STB_LOCAL:
|
|
|
|
symbol_vitrual_addr = rel_base_virtual_addr + sym.st_value;
|
|
|
|
break;
|
2024-02-27 22:10:34 +00:00
|
|
|
case STB_GLOBAL:
|
2024-03-26 15:17:59 +00:00
|
|
|
case STB_WEAK: {
|
2024-02-27 22:10:34 +00:00
|
|
|
rel_name = namesTlb + sym.st_name;
|
|
|
|
Resolve(rel_name, rel_sym_type, m, &symrec);
|
|
|
|
symbol_vitrual_addr = symrec.virtual_address;
|
2024-03-26 15:17:59 +00:00
|
|
|
} break;
|
2024-02-27 22:10:34 +00:00
|
|
|
default:
|
2024-03-26 15:17:59 +00:00
|
|
|
ASSERT_MSG(0, "unknown bind type {}", sym_bind);
|
2023-07-11 15:50:29 +00:00
|
|
|
}
|
2024-03-26 15:17:59 +00:00
|
|
|
rel_isResolved = (symbol_vitrual_addr != 0);
|
|
|
|
rel_value = (rel_isResolved ? symbol_vitrual_addr + addend : 0);
|
|
|
|
rel_name = symrec.name;
|
2024-02-27 22:10:34 +00:00
|
|
|
} break;
|
2024-02-23 20:57:57 +00:00
|
|
|
default:
|
2024-02-27 22:10:34 +00:00
|
|
|
LOG_INFO(Core_Linker, "UNK type {:#010x} rel symbol : {:#010x}", type, symbol);
|
2024-02-23 20:57:57 +00:00
|
|
|
}
|
2023-07-11 15:50:29 +00:00
|
|
|
|
2024-02-27 22:10:34 +00:00
|
|
|
if (rel_isResolved) {
|
|
|
|
VirtualMemory::memory_patch(rel_virtual_addr, rel_value);
|
|
|
|
} else {
|
|
|
|
LOG_INFO(Core_Linker, "function not patched! {}", rel_name);
|
|
|
|
}
|
|
|
|
};
|
2023-07-06 18:55:41 +00:00
|
|
|
|
2024-02-23 20:57:57 +00:00
|
|
|
u32 idx = 0;
|
|
|
|
for (auto* rel = m->dynamic_info.relocation_table;
|
2024-02-23 21:32:32 +00:00
|
|
|
reinterpret_cast<u8*>(rel) < reinterpret_cast<u8*>(m->dynamic_info.relocation_table) +
|
|
|
|
m->dynamic_info.relocation_table_size;
|
2024-02-23 20:57:57 +00:00
|
|
|
rel++, idx++) {
|
|
|
|
relocate(idx, rel, m, false);
|
|
|
|
}
|
|
|
|
idx = 0;
|
|
|
|
for (auto* rel = m->dynamic_info.jmp_relocation_table;
|
2024-02-23 21:32:32 +00:00
|
|
|
reinterpret_cast<u8*>(rel) < reinterpret_cast<u8*>(m->dynamic_info.jmp_relocation_table) +
|
|
|
|
m->dynamic_info.jmp_relocation_table_size;
|
2024-02-23 20:57:57 +00:00
|
|
|
rel++, idx++) {
|
|
|
|
relocate(idx, rel, m, true);
|
|
|
|
}
|
2023-07-11 15:50:29 +00:00
|
|
|
}
|
|
|
|
|
2024-03-26 10:57:18 +00:00
|
|
|
template <typename T>
|
|
|
|
bool contains(const std::vector<T>& vecObj, const T& element) {
|
|
|
|
auto it = std::find(vecObj.begin(), vecObj.end(), element);
|
|
|
|
return it != vecObj.end();
|
|
|
|
}
|
|
|
|
|
|
|
|
Module* Linker::FindExportedModule(const ModuleInfo& module, const LibraryInfo& library) {
|
|
|
|
// std::scoped_lock lock{m_mutex};
|
|
|
|
|
|
|
|
for (auto& m : m_modules) {
|
|
|
|
const auto& export_libs = m->dynamic_info.export_libs;
|
|
|
|
const auto& export_modules = m->dynamic_info.export_modules;
|
|
|
|
|
|
|
|
if (contains(export_libs, library) && contains(export_modules, module)) {
|
|
|
|
return m.get();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Linker::Resolve(const std::string& name, Loader::SymbolType sym_type, Module* m,
|
2024-02-23 20:57:57 +00:00
|
|
|
Loader::SymbolRecord* return_info) {
|
2024-03-26 10:57:18 +00:00
|
|
|
// std::scoped_lock lock{m_mutex};
|
2023-11-05 14:56:28 +00:00
|
|
|
const auto ids = Common::SplitString(name, '#');
|
2024-04-09 10:39:35 +00:00
|
|
|
if (ids.size() == 3) {
|
|
|
|
const auto* library = FindLibrary(*m, ids.at(1));
|
|
|
|
const auto* module = FindModule(*m, ids.at(2));
|
|
|
|
ASSERT_MSG(library && module, "Unable to find library and module");
|
|
|
|
|
|
|
|
Loader::SymbolResolver sr{};
|
|
|
|
sr.name = ids.at(0);
|
|
|
|
sr.library = library->name;
|
|
|
|
sr.library_version = library->version;
|
|
|
|
sr.module = module->name;
|
|
|
|
sr.module_version_major = module->version_major;
|
|
|
|
sr.module_version_minor = module->version_minor;
|
|
|
|
sr.type = sym_type;
|
|
|
|
|
|
|
|
const Loader::SymbolRecord* rec = nullptr;
|
|
|
|
|
|
|
|
rec = m_hle_symbols.FindSymbol(sr);
|
|
|
|
if (rec == nullptr) {
|
|
|
|
// check if it an export function
|
|
|
|
if (auto* p = FindExportedModule(*module, *library);
|
|
|
|
p != nullptr && p->export_sym.GetSize() > 0) {
|
|
|
|
rec = p->export_sym.FindSymbol(sr);
|
|
|
|
}
|
2024-03-26 10:57:18 +00:00
|
|
|
}
|
2024-04-09 10:39:35 +00:00
|
|
|
if (rec != nullptr) {
|
|
|
|
*return_info = *rec;
|
2024-02-23 20:57:57 +00:00
|
|
|
} else {
|
2024-04-09 10:39:35 +00:00
|
|
|
auto aeronid = AeroLib::FindByNid(sr.name.c_str());
|
|
|
|
if (aeronid) {
|
|
|
|
return_info->name = aeronid->name;
|
|
|
|
return_info->virtual_address = AeroLib::GetStub(aeronid->nid);
|
|
|
|
} else {
|
|
|
|
return_info->virtual_address = AeroLib::GetStub(sr.name.c_str());
|
|
|
|
return_info->name = "Unknown !!!";
|
|
|
|
}
|
|
|
|
LOG_ERROR(Core_Linker, "Linker: Stub resolved {} as {} (lib: {}, mod: {})", sr.name,
|
|
|
|
return_info->name, library->name, module->name);
|
2024-02-23 20:57:57 +00:00
|
|
|
}
|
2024-04-09 10:40:03 +00:00
|
|
|
} else {
|
2024-04-09 10:39:35 +00:00
|
|
|
return_info->virtual_address = 0;
|
|
|
|
return_info->name = name;
|
|
|
|
LOG_ERROR(Core_Linker, "Not Resolved {}", name);
|
2024-02-23 20:57:57 +00:00
|
|
|
}
|
2023-07-20 09:18:43 +00:00
|
|
|
}
|
|
|
|
|
2024-03-26 16:48:26 +00:00
|
|
|
u64 Linker::GetProcParam() {
|
|
|
|
// std::scoped_lock lock{m_mutex};
|
|
|
|
|
|
|
|
for (auto& m : m_modules) {
|
|
|
|
if (!m->elf.IsSharedLib()) {
|
|
|
|
return m->proc_param_virtual_addr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2024-02-23 20:57:57 +00:00
|
|
|
using exit_func_t = PS4_SYSV_ABI void (*)();
|
|
|
|
using entry_func_t = PS4_SYSV_ABI void (*)(EntryParams* params, exit_func_t atexit_func);
|
2024-03-26 16:13:27 +00:00
|
|
|
using module_ini_func_t = PS4_SYSV_ABI int (*)(size_t args, const void* argp, module_func_t func);
|
|
|
|
|
|
|
|
static PS4_SYSV_ABI int run_module(uint64_t addr, size_t args, const void* argp,
|
|
|
|
module_func_t func) {
|
|
|
|
return reinterpret_cast<module_ini_func_t>(addr)(args, argp, func);
|
|
|
|
}
|
|
|
|
|
|
|
|
int Linker::StartModule(Module* m, size_t args, const void* argp, module_func_t func) {
|
2024-03-27 06:41:14 +00:00
|
|
|
LOG_INFO(Core_Linker, "Module started : {}", m->file_name);
|
2024-03-26 16:13:27 +00:00
|
|
|
return run_module(m->dynamic_info.init_virtual_addr + m->base_virtual_addr, args, argp, func);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Linker::StartAllModules() {
|
|
|
|
std::scoped_lock lock{m_mutex};
|
|
|
|
|
|
|
|
for (auto& m : m_modules) {
|
|
|
|
if (m->elf.IsSharedLib()) {
|
|
|
|
StartModule(m.get(), 0, nullptr, nullptr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-07-20 09:18:43 +00:00
|
|
|
|
2023-07-21 05:03:36 +00:00
|
|
|
static PS4_SYSV_ABI void ProgramExitFunc() {
|
2023-10-26 20:29:05 +00:00
|
|
|
fmt::print("exit function called\n");
|
2023-07-20 09:18:43 +00:00
|
|
|
}
|
|
|
|
|
2024-02-27 22:10:34 +00:00
|
|
|
static void RunMainEntry(u64 addr, EntryParams* params, exit_func_t exit_func) {
|
2024-02-23 20:57:57 +00:00
|
|
|
// reinterpret_cast<entry_func_t>(addr)(params, exit_func); // can't be used, stack has to have
|
|
|
|
// a specific layout
|
2023-10-02 14:17:29 +00:00
|
|
|
|
2024-02-23 20:57:57 +00:00
|
|
|
asm volatile("andq $-16, %%rsp\n" // Align to 16 bytes
|
|
|
|
"subq $8, %%rsp\n" // videoout_basic expects the stack to be misaligned
|
2023-10-02 14:17:29 +00:00
|
|
|
|
2024-02-23 20:57:57 +00:00
|
|
|
// Kernel also pushes some more things here during process init
|
|
|
|
// at least: environment, auxv, possibly other things
|
2023-10-02 14:17:29 +00:00
|
|
|
|
2024-02-23 20:57:57 +00:00
|
|
|
"pushq 8(%1)\n" // copy EntryParams to top of stack like the kernel does
|
|
|
|
"pushq 0(%1)\n" // OpenOrbis expects to find it there
|
2023-10-02 14:17:29 +00:00
|
|
|
|
2024-02-23 20:57:57 +00:00
|
|
|
"movq %1, %%rdi\n" // also pass params and exit func
|
|
|
|
"movq %2, %%rsi\n" // as before
|
2023-10-02 14:17:29 +00:00
|
|
|
|
2024-02-23 20:57:57 +00:00
|
|
|
"jmp *%0\n" // can't use call here, as that would mangle the prepared stack.
|
|
|
|
// there's no coming back
|
|
|
|
:
|
|
|
|
: "r"(addr), "r"(params), "r"(exit_func)
|
2024-04-13 21:35:48 +00:00
|
|
|
: "rax", "rsi", "rdi", "rsp");
|
2023-07-20 09:18:43 +00:00
|
|
|
}
|
|
|
|
|
2023-11-05 23:11:54 +00:00
|
|
|
void Linker::Execute() {
|
2024-03-11 11:26:33 +00:00
|
|
|
if (Config::debugDump()) {
|
|
|
|
DebugDump();
|
|
|
|
}
|
|
|
|
|
2024-04-13 21:35:48 +00:00
|
|
|
Libraries::Kernel::pthreadInitSelfMainThread();
|
|
|
|
// Relocate all modules
|
2024-03-26 15:33:48 +00:00
|
|
|
for (const auto& m : m_modules) {
|
|
|
|
Relocate(m.get());
|
|
|
|
}
|
2024-03-26 16:13:27 +00:00
|
|
|
StartAllModules();
|
2023-07-20 09:18:43 +00:00
|
|
|
EntryParams p{};
|
|
|
|
p.argc = 1;
|
2024-02-23 20:57:57 +00:00
|
|
|
p.argv[0] = "eboot.bin"; // hmm should be ok?
|
2023-07-20 09:18:43 +00:00
|
|
|
|
2024-03-26 16:13:27 +00:00
|
|
|
for (auto& m : m_modules) {
|
|
|
|
if (!m->elf.IsSharedLib()) {
|
|
|
|
RunMainEntry(m->elf.GetElfEntry() + m->base_virtual_addr, &p, ProgramExitFunc);
|
|
|
|
}
|
|
|
|
}
|
2023-10-26 19:55:13 +00:00
|
|
|
}
|
2023-11-05 23:11:54 +00:00
|
|
|
|
2024-03-11 11:26:33 +00:00
|
|
|
void Linker::DebugDump() {
|
|
|
|
std::scoped_lock lock{m_mutex};
|
|
|
|
const auto& log_dir = Common::FS::GetUserPath(Common::FS::PathType::LogDir);
|
|
|
|
const std::filesystem::path debug(log_dir / "debugdump");
|
|
|
|
std::filesystem::create_directory(debug);
|
|
|
|
for (const auto& m : m_modules) {
|
|
|
|
// TODO make a folder with game id for being more unique?
|
|
|
|
const std::filesystem::path filepath(debug / m.get()->file_name);
|
|
|
|
std::filesystem::create_directory(filepath);
|
|
|
|
m.get()->import_sym.DebugDump(filepath / "imports.txt");
|
|
|
|
m.get()->export_sym.DebugDump(filepath / "exports.txt");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-05 23:11:54 +00:00
|
|
|
} // namespace Core
|