[jit] fix Super Mario 64 in SM3D: All-Stars (#3950)

jit service had wrong check for module versions
missing handlers for some funcs
the page cache i added interfered with jit (gee who would've tought)

Signed-off-by: lizzie <lizzie@eden-emu.dev>

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3950
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: crueter <crueter@eden-emu.dev>
This commit is contained in:
lizzie 2026-05-13 19:02:33 +02:00 committed by crueter
parent 7e84f9ef59
commit b89cd6903c
No known key found for this signature in database
GPG key ID: 425ACD2D4830EBC6
7 changed files with 198 additions and 213 deletions

View file

@ -36,7 +36,7 @@ public:
u64 MemoryRead64(u32 vaddr) override;
std::optional<u32> MemoryReadCode(u32 vaddr) override;
void InstructionSynchronizationBarrierRaised() override {
last_code_addr = 0; //reset back, force refetch
last_code_addr = u64(-1); //reset back, force refetch
}
void MemoryWrite8(u32 vaddr, u8 value) override;
void MemoryWrite16(u32 vaddr, u16 value) override;
@ -54,7 +54,7 @@ public:
void ReturnException(u32 pc, Dynarmic::HaltReason hr);
//
Dynarmic::CodePage cached_code_page;
u64 last_code_addr = 0;
u64 last_code_addr = u64(-1);
ArmDynarmic32& m_parent;
Core::Memory::Memory& m_memory;
Kernel::KProcess* m_process{};

View file

@ -45,7 +45,6 @@ Dynarmic::A64::Vector DynarmicCallbacks64::MemoryRead128(u64 vaddr) {
std::optional<u32> DynarmicCallbacks64::MemoryReadCode(u64 vaddr) {
if (!m_memory.IsValidVirtualAddressRange(vaddr, sizeof(u32)))
return std::nullopt;
// return m_memory.Read32(vaddr);
auto const aligned_vaddr = vaddr & ~Core::Memory::YUZU_PAGEMASK;
if (last_code_addr != aligned_vaddr) {
m_memory.ReadBlock(aligned_vaddr, &cached_code_page, sizeof(cached_code_page));
@ -103,6 +102,7 @@ bool DynarmicCallbacks64::MemoryWriteExclusive128(u64 vaddr, Dynarmic::A64::Vect
}
void DynarmicCallbacks64::InstructionCacheOperationRaised(Dynarmic::A64::InstructionCacheOperation op, u64 value) {
last_code_addr = u64(-1); //invalidate cached page
switch (op) {
case Dynarmic::A64::InstructionCacheOperation::InvalidateByVAToPoU: {
static constexpr u64 ICACHE_LINE_SIZE = 64;
@ -128,7 +128,7 @@ void DynarmicCallbacks64::ExceptionRaised(u64 pc, Dynarmic::A64::Exception excep
case Dynarmic::A64::Exception::SendEvent:
case Dynarmic::A64::Exception::SendEventLocal:
case Dynarmic::A64::Exception::Yield:
LOG_TRACE(Core_ARM, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})", static_cast<std::size_t>(exception), pc, m_memory.Read32(pc));
LOG_TRACE(Core_ARM, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X}, cached = {:08X})", std::size_t(exception), pc, m_memory.Read32(pc), MemoryReadCode(pc).value_or(0));
return;
case Dynarmic::A64::Exception::NoExecuteFault:
LOG_CRITICAL(Core_ARM, "Cannot execute instruction at unmapped address {:#016x}", pc);

View file

@ -43,7 +43,7 @@ public:
Dynarmic::A64::Vector MemoryRead128(u64 vaddr) override;
std::optional<u32> MemoryReadCode(u64 vaddr) override;
void InstructionSynchronizationBarrierRaised() override {
last_code_addr = 0; //reset back, force refetch
last_code_addr = u64(-1); //reset back, force refetch
}
void MemoryWrite8(u64 vaddr, u8 value) override;
void MemoryWrite16(u64 vaddr, u16 value) override;
@ -65,7 +65,7 @@ public:
void ReturnException(u64 pc, Dynarmic::HaltReason hr);
Dynarmic::CodePage cached_code_page;
u64 last_code_addr = 0;
u64 last_code_addr = u64(-1);
ArmDynarmic64& m_parent;
Core::Memory::Memory& m_memory;
u64 m_tpidrro_el0{};

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -13,117 +16,111 @@ using namespace Common::ELF;
namespace Core {
namespace Symbols {
template <typename Word, typename ELFSymbol, typename ByteReader>
static Symbols GetSymbols(ByteReader ReadBytes) {
const auto Read8{[&](u64 index) {
struct ModuleHeaderLocation {
u32 version;
u32 header_offset;
u32 version_offset;
};
static_assert(sizeof(ModuleHeaderLocation) == 0x0C);
struct ModuleHeader {
u32 signature;
u32 dynamic_offset;
u32 bss_start_offset;
u32 bss_end_offset;
u32 exception_info_start_offset;
u32 exception_info_end_offset;
u32 module_offset;
u32 relro_start_offset;
u32 full_relro_end_offset;
u32 nx_debug_link_start_offset;
u32 nx_debug_link_end_offset;
u32 note_gnu_build_id_start_offset;
u32 note_gnu_build_id_end_offset;
};
static_assert(sizeof(ModuleHeader) == 0x34);
struct Mod32 {
using Sym = Elf32_Sym;
using Dyn = Elf32_Dyn;
};
struct Mod64 {
using Sym = Elf64_Sym;
using Dyn = Elf64_Dyn;
};
template <typename M, typename F>
static Symbols GetSymbols(F&& ReadBytes) {
const auto Read8 = [&](u64 index) {
u8 ret;
ReadBytes(&ret, index, sizeof(u8));
return ret;
}};
const auto Read32{[&](u64 index) {
u32 ret;
ReadBytes(&ret, index, sizeof(u32));
return ret;
}};
const auto ReadWord{[&](u64 index) {
Word ret;
ReadBytes(&ret, index, sizeof(Word));
return ret;
}};
const u32 mod_offset = Read32(4);
if (Read32(mod_offset) != Common::MakeMagic('M', 'O', 'D', '0')) {
};
ModuleHeaderLocation loc{};
ReadBytes(&loc, 0, sizeof(ModuleHeaderLocation));
ModuleHeader hdr;
ReadBytes(&hdr, loc.header_offset, sizeof(ModuleHeader));
if (hdr.signature != Common::MakeMagic('M', 'O', 'D', '0')) {
return {};
}
VAddr string_table_offset{};
VAddr symbol_table_offset{};
u64 symbol_entry_size{};
const auto dynamic_offset = Read32(mod_offset + 0x4) + mod_offset;
VAddr dynamic_index = dynamic_offset;
VAddr strtab_offs{};
VAddr symtab_offs{};
u64 syment_size = sizeof(typename M::Sym);
VAddr dynamic_offset = loc.header_offset + hdr.dynamic_offset;
while (true) {
const Word tag = ReadWord(dynamic_index);
const Word value = ReadWord(dynamic_index + sizeof(Word));
dynamic_index += 2 * sizeof(Word);
if (tag == ElfDtNull) {
typename M::Dyn dyn;
ReadBytes(&dyn, dynamic_offset, sizeof(typename M::Dyn));
dynamic_offset += sizeof(typename M::Dyn);
if (dyn.d_tag == ElfDtNull) {
break;
}
if (tag == ElfDtStrtab) {
string_table_offset = value;
} else if (tag == ElfDtSymtab) {
symbol_table_offset = value;
} else if (tag == ElfDtSyment) {
symbol_entry_size = value;
if (dyn.d_tag == ElfDtStrtab) {
strtab_offs = dyn.d_un.d_ptr;
} else if (dyn.d_tag == ElfDtSymtab) {
symtab_offs = dyn.d_un.d_ptr;
} else if (dyn.d_tag == ElfDtSyment) {
syment_size = dyn.d_un.d_val;
}
}
if (string_table_offset == 0 || symbol_table_offset == 0 || symbol_entry_size == 0) {
return {};
}
Symbols out;
VAddr symbol_index = symbol_table_offset;
while (symbol_index < string_table_offset) {
ELFSymbol symbol{};
ReadBytes(&symbol, symbol_index, sizeof(ELFSymbol));
VAddr string_offset = string_table_offset + symbol.st_name;
std::string name;
for (u8 c = Read8(string_offset); c != 0; c = Read8(++string_offset)) {
name += static_cast<char>(c);
if (strtab_offs > 0 && symtab_offs > 0) {
Symbols out;
VAddr symbol_index = symtab_offs;
while (symbol_index < strtab_offs) {
typename M::Sym symbol{};
ReadBytes(&symbol, symbol_index, sizeof(typename M::Sym));
VAddr offs = strtab_offs + symbol.st_name;
std::string name{};
for (u8 c = Read8(offs); c != 0; c = Read8(++offs))
name += char(c);
symbol_index += syment_size;
out[name] = std::make_pair(symbol.st_value, symbol.st_size);
}
symbol_index += symbol_entry_size;
out[name] = std::make_pair(symbol.st_value, symbol.st_size);
return out;
}
return out;
return {};
}
Symbols GetSymbols(VAddr base, Core::Memory::Memory& memory, bool is_64) {
const auto ReadBytes{
[&](void* ptr, size_t offset, size_t size) { memory.ReadBlock(base + offset, ptr, size); }};
if (is_64) {
return GetSymbols<u64, Elf64_Sym>(ReadBytes);
} else {
return GetSymbols<u32, Elf32_Sym>(ReadBytes);
}
const auto f = [base, &memory](void* ptr, size_t offset, size_t size) {
memory.ReadBlock(base + offset, ptr, size);
};
return is_64 ? GetSymbols<Mod64>(f) : GetSymbols<Mod32>(f);
}
Symbols GetSymbols(std::span<const u8> data, bool is_64) {
const auto ReadBytes{[&](void* ptr, size_t offset, size_t size) {
const auto f = [data](void* ptr, size_t offset, size_t size) {
std::memcpy(ptr, data.data() + offset, size);
}};
if (is_64) {
return GetSymbols<u64, Elf64_Sym>(ReadBytes);
} else {
return GetSymbols<u32, Elf32_Sym>(ReadBytes);
}
};
return is_64 ? GetSymbols<Mod64>(f) : GetSymbols<Mod32>(f);
}
std::optional<std::string> GetSymbolName(const Symbols& symbols, VAddr addr) {
const auto iter = std::find_if(symbols.cbegin(), symbols.cend(), [addr](const auto& pair) {
const auto& [name, sym_info] = pair;
const auto& [start_address, size] = sym_info;
const auto end_address = start_address + size;
return addr >= start_address && addr < end_address;
const auto it = std::find_if(symbols.cbegin(), symbols.cend(), [addr](const auto& e) {
auto const [start, size] = e.second;
auto const end = start + size;
return addr >= start && addr < end;
});
if (iter == symbols.cend()) {
return std::nullopt;
}
return iter->first;
return it != symbols.cend() ? std::optional<std::string>{it->first} : std::nullopt;
}
} // namespace Symbols