2024-02-23 21:32:32 +00:00
|
|
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
|
2024-06-05 19:08:18 +00:00
|
|
|
#include "common/alignment.h"
|
|
|
|
#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"
|
2024-06-01 20:50:03 +00:00
|
|
|
#include "common/thread.h"
|
2023-11-05 23:11:54 +00:00
|
|
|
#include "core/aerolib/aerolib.h"
|
|
|
|
#include "core/aerolib/stubs.h"
|
2024-06-05 19:08:18 +00:00
|
|
|
#include "core/libraries/kernel/memory_management.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-06-21 15:22:37 +00:00
|
|
|
#include "core/memory.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-06-05 19:08:18 +00:00
|
|
|
using ExitFunc = PS4_SYSV_ABI void (*)();
|
2023-05-25 10:16:53 +00:00
|
|
|
|
2024-06-05 19:08:18 +00:00
|
|
|
static PS4_SYSV_ABI void ProgramExitFunc() {
|
|
|
|
fmt::print("exit function called\n");
|
2023-05-23 16:39:24 +00:00
|
|
|
}
|
|
|
|
|
2024-06-05 19:08:18 +00:00
|
|
|
static void RunMainEntry(VAddr addr, EntryParams* params, ExitFunc exit_func) {
|
|
|
|
// reinterpret_cast<entry_func_t>(addr)(params, exit_func); // can't be used, stack has to have
|
|
|
|
// a specific layout
|
|
|
|
asm volatile("andq $-16, %%rsp\n" // Align to 16 bytes
|
|
|
|
"subq $8, %%rsp\n" // videoout_basic expects the stack to be misaligned
|
2023-05-23 16:39:24 +00:00
|
|
|
|
2024-06-05 19:08:18 +00:00
|
|
|
// Kernel also pushes some more things here during process init
|
|
|
|
// at least: environment, auxv, possibly other things
|
|
|
|
|
|
|
|
"pushq 8(%1)\n" // copy EntryParams to top of stack like the kernel does
|
|
|
|
"pushq 0(%1)\n" // OpenOrbis expects to find it there
|
|
|
|
|
|
|
|
"movq %1, %%rdi\n" // also pass params and exit func
|
|
|
|
"movq %2, %%rsi\n" // as before
|
|
|
|
|
|
|
|
"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)
|
|
|
|
: "rax", "rsi", "rdi");
|
2023-06-14 04:47:44 +00:00
|
|
|
}
|
2023-10-26 20:07:15 +00:00
|
|
|
|
2024-06-21 15:22:37 +00:00
|
|
|
Linker::Linker() : memory{Memory::Instance()} {}
|
2023-10-26 20:07:15 +00:00
|
|
|
|
|
|
|
Linker::~Linker() = default;
|
|
|
|
|
2024-06-05 19:08:18 +00:00
|
|
|
void Linker::Execute() {
|
|
|
|
if (Config::debugDump()) {
|
|
|
|
DebugDump();
|
2024-02-27 22:10:34 +00:00
|
|
|
}
|
|
|
|
|
2024-06-05 19:08:18 +00:00
|
|
|
// Calculate static TLS size.
|
|
|
|
for (const auto& module : m_modules) {
|
|
|
|
static_tls_size += module->tls.image_size;
|
|
|
|
module->tls.offset = static_tls_size;
|
|
|
|
}
|
2024-02-27 22:10:34 +00:00
|
|
|
|
2024-06-05 19:08:18 +00:00
|
|
|
// Relocate all modules
|
|
|
|
for (const auto& m : m_modules) {
|
|
|
|
Relocate(m.get());
|
2023-10-26 20:07:15 +00:00
|
|
|
}
|
2023-05-23 04:48:25 +00:00
|
|
|
|
2024-06-21 15:22:37 +00:00
|
|
|
// Configure used flexible memory size.
|
|
|
|
if (u64* flexible_size = GetProcParam()->mem_param->flexible_memory_size) {
|
|
|
|
memory->SetTotalFlexibleSize(*flexible_size);
|
|
|
|
}
|
|
|
|
|
2024-06-05 19:08:18 +00:00
|
|
|
// Init primary thread.
|
|
|
|
Common::SetCurrentThreadName("GAME_MainThread");
|
|
|
|
Libraries::Kernel::pthreadInitSelfMainThread();
|
|
|
|
InitTlsForThread(true);
|
2023-05-23 07:47:56 +00:00
|
|
|
|
2024-06-05 19:08:18 +00:00
|
|
|
// Start shared library modules
|
|
|
|
for (auto& m : m_modules) {
|
|
|
|
if (m->IsSharedLib()) {
|
|
|
|
m->Start(0, nullptr, nullptr);
|
2024-02-23 20:57:57 +00:00
|
|
|
}
|
|
|
|
}
|
2023-06-08 09:51:11 +00:00
|
|
|
|
2024-06-05 19:08:18 +00:00
|
|
|
// Start main module.
|
|
|
|
EntryParams p{};
|
|
|
|
p.argc = 1;
|
|
|
|
p.argv[0] = "eboot.bin";
|
2023-06-13 04:43:58 +00:00
|
|
|
|
2024-06-05 19:08:18 +00:00
|
|
|
for (auto& m : m_modules) {
|
|
|
|
if (!m->IsSharedLib()) {
|
|
|
|
RunMainEntry(m->GetEntryAddress(), &p, ProgramExitFunc);
|
2024-02-23 20:57:57 +00:00
|
|
|
}
|
|
|
|
}
|
2023-06-18 14:54:22 +00:00
|
|
|
}
|
|
|
|
|
2024-06-21 16:02:49 +00:00
|
|
|
s32 Linker::LoadModule(const std::filesystem::path& elf_name, bool is_dynamic) {
|
2024-06-05 19:08:18 +00:00
|
|
|
std::scoped_lock lk{mutex};
|
|
|
|
|
|
|
|
if (!std::filesystem::exists(elf_name)) {
|
|
|
|
LOG_ERROR(Core_Linker, "Provided file {} does not exist", elf_name.string());
|
|
|
|
return -1;
|
2024-02-23 20:57:57 +00:00
|
|
|
}
|
2023-06-18 14:54:22 +00:00
|
|
|
|
2024-06-21 15:22:37 +00:00
|
|
|
auto module = std::make_unique<Module>(memory, elf_name, max_tls_index);
|
2024-06-05 19:08:18 +00:00
|
|
|
if (!module->IsValid()) {
|
|
|
|
LOG_ERROR(Core_Linker, "Provided file {} is not valid ELF file", elf_name.string());
|
|
|
|
return -1;
|
|
|
|
}
|
2023-06-26 15:12:19 +00:00
|
|
|
|
2024-06-21 16:02:49 +00:00
|
|
|
num_static_modules += !is_dynamic;
|
2024-06-05 19:08:18 +00:00
|
|
|
m_modules.emplace_back(std::move(module));
|
|
|
|
return m_modules.size() - 1;
|
2023-07-04 15:34:23 +00:00
|
|
|
}
|
2024-02-27 22:10:34 +00:00
|
|
|
|
2024-06-15 11:36:07 +00:00
|
|
|
Module* Linker::FindByAddress(VAddr address) {
|
|
|
|
for (auto& module : m_modules) {
|
|
|
|
const VAddr base = module->GetBaseAddress();
|
|
|
|
if (address >= base && address < base + module->aligned_base_size) {
|
|
|
|
return module.get();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2024-06-05 19:08:18 +00:00
|
|
|
void Linker::Relocate(Module* module) {
|
2024-06-15 11:36:07 +00:00
|
|
|
module->ForEachRelocation([&](elf_relocation* rel, u32 i, bool isJmpRel) {
|
|
|
|
const u32 bit_idx =
|
|
|
|
(isJmpRel ? module->dynamic_info.relocation_table_size / sizeof(elf_relocation) : 0) +
|
|
|
|
i;
|
|
|
|
if (module->TestRelaBit(bit_idx)) {
|
|
|
|
return;
|
|
|
|
}
|
2024-02-27 22:10:34 +00:00
|
|
|
auto type = rel->GetType();
|
|
|
|
auto symbol = rel->GetSymbol();
|
|
|
|
auto addend = rel->rel_addend;
|
2024-06-05 19:08:18 +00:00
|
|
|
auto* symbol_table = module->dynamic_info.symbol_table;
|
|
|
|
auto* namesTlb = module->dynamic_info.str_table;
|
2024-02-27 22:10:34 +00:00
|
|
|
|
2024-06-05 19:08:18 +00:00
|
|
|
const VAddr rel_base_virtual_addr = module->GetBaseAddress();
|
|
|
|
const VAddr rel_virtual_addr = rel_base_virtual_addr + rel->rel_offset;
|
|
|
|
bool rel_is_resolved = false;
|
2024-02-27 22:10:34 +00:00
|
|
|
u64 rel_value = 0;
|
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;
|
2024-06-05 19:08:18 +00:00
|
|
|
rel_is_resolved = true;
|
2023-07-11 15:50:29 +00:00
|
|
|
break;
|
2024-03-26 15:17:59 +00:00
|
|
|
case R_X86_64_DTPMOD64:
|
2024-06-05 19:08:18 +00:00
|
|
|
rel_value = static_cast<u64>(module->tls.modid);
|
|
|
|
rel_is_resolved = true;
|
2024-03-26 15:17:59 +00:00
|
|
|
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-06-05 19:08:18 +00:00
|
|
|
auto sym = symbol_table[symbol];
|
2024-02-27 22:10:34 +00:00
|
|
|
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
|
|
|
}
|
2024-06-05 19:08:18 +00:00
|
|
|
|
|
|
|
if (sym_visibility != 0) {
|
2024-02-27 22:10:34 +00:00
|
|
|
LOG_INFO(Core_Linker, "symbol visilibity !=0");
|
2023-07-11 15:50:29 +00:00
|
|
|
}
|
2024-06-05 19:08:18 +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;
|
2024-06-15 11:36:07 +00:00
|
|
|
module->SetRelaBit(bit_idx);
|
2024-03-26 15:17:59 +00:00
|
|
|
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;
|
2024-06-15 11:36:07 +00:00
|
|
|
if (Resolve(rel_name, rel_sym_type, module, &symrec)) {
|
|
|
|
// Only set the rela bit if the symbol was actually resolved and not stubbed.
|
|
|
|
module->SetRelaBit(bit_idx);
|
|
|
|
}
|
2024-02-27 22:10:34 +00:00
|
|
|
symbol_vitrual_addr = symrec.virtual_address;
|
2024-06-05 19:08:18 +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-06-05 19:08:18 +00:00
|
|
|
rel_is_resolved = (symbol_vitrual_addr != 0);
|
|
|
|
rel_value = (rel_is_resolved ? symbol_vitrual_addr + addend : 0);
|
2024-03-26 15:17:59 +00:00
|
|
|
rel_name = symrec.name;
|
2024-06-05 19:08:18 +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-06-05 19:08:18 +00:00
|
|
|
if (rel_is_resolved) {
|
2024-02-27 22:10:34 +00:00
|
|
|
VirtualMemory::memory_patch(rel_virtual_addr, rel_value);
|
|
|
|
} else {
|
|
|
|
LOG_INFO(Core_Linker, "function not patched! {}", rel_name);
|
|
|
|
}
|
2024-06-05 19:08:18 +00:00
|
|
|
});
|
2023-07-11 15:50:29 +00:00
|
|
|
}
|
|
|
|
|
2024-06-05 19:08:18 +00:00
|
|
|
const Module* Linker::FindExportedModule(const ModuleInfo& module, const LibraryInfo& library) {
|
|
|
|
const auto it = std::ranges::find_if(m_modules, [&](const auto& m) {
|
|
|
|
return std::ranges::contains(m->GetExportLibs(), library) &&
|
|
|
|
std::ranges::contains(m->GetExportModules(), module);
|
|
|
|
});
|
|
|
|
return it == m_modules.end() ? nullptr : it->get();
|
2024-03-26 10:57:18 +00:00
|
|
|
}
|
|
|
|
|
2024-06-15 11:36:07 +00:00
|
|
|
bool Linker::Resolve(const std::string& name, Loader::SymbolType sym_type, Module* m,
|
2024-02-23 20:57:57 +00:00
|
|
|
Loader::SymbolRecord* return_info) {
|
2023-11-05 14:56:28 +00:00
|
|
|
const auto ids = Common::SplitString(name, '#');
|
2024-06-05 19:08:18 +00:00
|
|
|
if (ids.size() != 3) {
|
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-06-15 11:36:07 +00:00
|
|
|
return false;
|
2024-02-23 20:57:57 +00:00
|
|
|
}
|
2024-03-26 16:48:26 +00:00
|
|
|
|
2024-06-05 19:08:18 +00:00
|
|
|
const LibraryInfo* library = m->FindLibrary(ids[1]);
|
|
|
|
const ModuleInfo* module = m->FindModule(ids[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 auto* record = m_hle_symbols.FindSymbol(sr);
|
|
|
|
if (!record) {
|
|
|
|
// Check if it an export function
|
|
|
|
const auto* p = FindExportedModule(*module, *library);
|
|
|
|
if (p && p->export_sym.GetSize() > 0) {
|
|
|
|
record = p->export_sym.FindSymbol(sr);
|
2024-03-26 16:48:26 +00:00
|
|
|
}
|
|
|
|
}
|
2024-06-05 19:08:18 +00:00
|
|
|
if (record) {
|
|
|
|
*return_info = *record;
|
2024-06-15 11:36:07 +00:00
|
|
|
return true;
|
2024-06-05 19:08:18 +00:00
|
|
|
}
|
2024-03-26 16:13:27 +00:00
|
|
|
|
2024-06-05 19:08:18 +00:00
|
|
|
const 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 !!!";
|
2024-03-26 16:13:27 +00:00
|
|
|
}
|
2024-06-05 19:08:18 +00:00
|
|
|
LOG_ERROR(Core_Linker, "Linker: Stub resolved {} as {} (lib: {}, mod: {})", sr.name,
|
|
|
|
return_info->name, library->name, module->name);
|
2024-06-15 11:36:07 +00:00
|
|
|
return false;
|
2024-03-26 16:13:27 +00:00
|
|
|
}
|
2023-07-20 09:18:43 +00:00
|
|
|
|
2024-06-05 19:08:18 +00:00
|
|
|
void* Linker::TlsGetAddr(u64 module_index, u64 offset) {
|
|
|
|
std::scoped_lock lk{mutex};
|
2023-07-20 09:18:43 +00:00
|
|
|
|
2024-06-05 19:08:18 +00:00
|
|
|
DtvEntry* dtv_table = GetTcbBase()->tcb_dtv;
|
2024-06-15 11:36:07 +00:00
|
|
|
if (dtv_table[0].counter != dtv_generation_counter) {
|
|
|
|
// Generation counter changed, a dynamic module was either loaded or unloaded.
|
|
|
|
const u32 old_num_dtvs = dtv_table[1].counter;
|
|
|
|
ASSERT_MSG(max_tls_index > old_num_dtvs, "Module unloading unsupported");
|
|
|
|
// Module was loaded, increase DTV table size.
|
|
|
|
DtvEntry* new_dtv_table = new DtvEntry[max_tls_index + 2];
|
|
|
|
std::memcpy(new_dtv_table + 2, dtv_table + 2, old_num_dtvs * sizeof(DtvEntry));
|
|
|
|
new_dtv_table[0].counter = dtv_generation_counter;
|
|
|
|
new_dtv_table[1].counter = max_tls_index;
|
|
|
|
delete[] dtv_table;
|
|
|
|
|
|
|
|
// Update TCB pointer.
|
|
|
|
GetTcbBase()->tcb_dtv = new_dtv_table;
|
|
|
|
dtv_table = new_dtv_table;
|
|
|
|
}
|
2023-10-02 14:17:29 +00:00
|
|
|
|
2024-06-15 11:36:07 +00:00
|
|
|
u8* addr = dtv_table[module_index + 1].pointer;
|
|
|
|
if (!addr) {
|
|
|
|
// Module was just loaded by above code. Allocate TLS block for it.
|
|
|
|
Module* module = m_modules[module_index - 1].get();
|
|
|
|
const u32 init_image_size = module->tls.init_image_size;
|
|
|
|
u8* dest = reinterpret_cast<u8*>(heap_api_func(module->tls.image_size));
|
|
|
|
const u8* src = reinterpret_cast<const u8*>(module->tls.image_virtual_addr);
|
|
|
|
std::memcpy(dest, src, init_image_size);
|
|
|
|
std::memset(dest + init_image_size, 0, module->tls.image_size - init_image_size);
|
|
|
|
dtv_table[module_index + 1].pointer = dest;
|
|
|
|
addr = dest;
|
|
|
|
}
|
|
|
|
return addr + offset;
|
2023-07-20 09:18:43 +00:00
|
|
|
}
|
|
|
|
|
2024-06-05 19:08:18 +00:00
|
|
|
void Linker::InitTlsForThread(bool is_primary) {
|
|
|
|
static constexpr size_t TcbSize = 0x40;
|
|
|
|
static constexpr size_t TlsAllocAlign = 0x20;
|
|
|
|
const size_t total_tls_size = Common::AlignUp(static_tls_size, TlsAllocAlign) + TcbSize;
|
|
|
|
|
|
|
|
// The kernel module has a few different paths for TLS allocation.
|
|
|
|
// For SDK < 1.7 it allocates both main and secondary thread blocks using libc mspace/malloc.
|
|
|
|
// In games compiled with newer SDK, the main thread gets mapped from flexible memory,
|
|
|
|
// with addr = 0, so system managed area. Here we will only implement the latter.
|
|
|
|
void* addr_out{};
|
|
|
|
if (is_primary) {
|
|
|
|
const size_t tls_aligned = Common::AlignUp(total_tls_size, 16_KB);
|
|
|
|
const int ret = Libraries::Kernel::sceKernelMapNamedFlexibleMemory(
|
|
|
|
&addr_out, tls_aligned, 3, 0, "SceKernelPrimaryTcbTls");
|
|
|
|
ASSERT_MSG(ret == 0, "Unable to allocate TLS+TCB for the primary thread");
|
|
|
|
} else {
|
|
|
|
if (heap_api_func) {
|
|
|
|
addr_out = heap_api_func(total_tls_size);
|
|
|
|
} else {
|
|
|
|
addr_out = std::malloc(total_tls_size);
|
|
|
|
}
|
2024-03-11 11:26:33 +00:00
|
|
|
}
|
|
|
|
|
2024-06-05 19:08:18 +00:00
|
|
|
// Initialize allocated memory and allocate DTV table.
|
|
|
|
const u32 num_dtvs = max_tls_index;
|
|
|
|
std::memset(addr_out, 0, total_tls_size);
|
|
|
|
DtvEntry* dtv_table = new DtvEntry[num_dtvs + 2];
|
2024-06-01 20:50:03 +00:00
|
|
|
|
2024-06-05 19:08:18 +00:00
|
|
|
// Initialize thread control block
|
|
|
|
u8* addr = reinterpret_cast<u8*>(addr_out);
|
|
|
|
Tcb* tcb = reinterpret_cast<Tcb*>(addr + static_tls_size);
|
|
|
|
tcb->tcb_self = tcb;
|
|
|
|
tcb->tcb_dtv = dtv_table;
|
2023-07-20 09:18:43 +00:00
|
|
|
|
2024-06-05 19:08:18 +00:00
|
|
|
// Dtv[0] is the generation counter. libkernel puts their number into dtv[1] (why?)
|
|
|
|
dtv_table[0].counter = dtv_generation_counter;
|
|
|
|
dtv_table[1].counter = num_dtvs;
|
|
|
|
|
|
|
|
// Copy init images to TLS thread blocks and map them to DTV slots.
|
2024-06-21 16:02:49 +00:00
|
|
|
for (u32 i = 0; i < num_static_modules; i++) {
|
|
|
|
auto* module = m_modules[i].get();
|
2024-06-05 19:08:18 +00:00
|
|
|
if (module->tls.image_size == 0) {
|
2024-05-01 10:38:41 +00:00
|
|
|
continue;
|
|
|
|
}
|
2024-06-05 19:08:18 +00:00
|
|
|
u8* dest = reinterpret_cast<u8*>(addr + static_tls_size - module->tls.offset);
|
|
|
|
const u8* src = reinterpret_cast<const u8*>(module->tls.image_virtual_addr);
|
|
|
|
std::memcpy(dest, src, module->tls.init_image_size);
|
|
|
|
tcb->tcb_dtv[module->tls.modid + 1].pointer = dest;
|
2024-03-26 16:13:27 +00:00
|
|
|
}
|
2024-06-05 19:08:18 +00:00
|
|
|
|
|
|
|
// Set pointer to FS base
|
|
|
|
SetTcbBase(tcb);
|
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() {
|
|
|
|
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?
|
2024-06-05 19:08:18 +00:00
|
|
|
const std::filesystem::path filepath(debug / m.get()->file.stem());
|
2024-03-11 11:26:33 +00:00
|
|
|
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
|