mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-03 21:41:26 +12:00
LLVM: load .pdata section
This commit is contained in:
parent
4fc8276f0f
commit
ad72168143
2 changed files with 51 additions and 82 deletions
|
@ -54,10 +54,6 @@ static void* const s_memory = []() -> void*
|
||||||
static u8* s_code_addr;
|
static u8* s_code_addr;
|
||||||
static u64 s_code_size;
|
static u64 s_code_size;
|
||||||
|
|
||||||
// EH frames
|
|
||||||
static u8* s_unwind_info;
|
|
||||||
static u64 s_unwind_size;
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
static std::vector<std::vector<RUNTIME_FUNCTION>> s_unwind; // .pdata
|
static std::vector<std::vector<RUNTIME_FUNCTION>> s_unwind; // .pdata
|
||||||
#endif
|
#endif
|
||||||
|
@ -193,8 +189,27 @@ struct MemoryManager final : llvm::RTDyldMemoryManager
|
||||||
|
|
||||||
virtual void registerEHFrames(u8* addr, u64 load_addr, std::size_t size) override
|
virtual void registerEHFrames(u8* addr, u64 load_addr, std::size_t size) override
|
||||||
{
|
{
|
||||||
s_unwind_info = addr;
|
#ifdef _WIN32
|
||||||
s_unwind_size = size;
|
// Use s_memory as a BASE, compute the difference
|
||||||
|
const u64 code_diff = (u64)s_code_addr - (u64)s_memory;
|
||||||
|
const u64 unwind_diff = (u64)addr - (u64)s_memory;
|
||||||
|
|
||||||
|
// Fix RUNTIME_FUNCTION records (.pdata section)
|
||||||
|
auto& pdata = s_unwind.back();
|
||||||
|
|
||||||
|
for (auto& rf : pdata)
|
||||||
|
{
|
||||||
|
rf.BeginAddress += static_cast<DWORD>(code_diff);
|
||||||
|
rf.EndAddress += static_cast<DWORD>(code_diff);
|
||||||
|
rf.UnwindData += static_cast<DWORD>(unwind_diff);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register .xdata UNWIND_INFO structs
|
||||||
|
if (!RtlAddFunctionTable(pdata.data(), (DWORD)pdata.size(), (u64)s_memory))
|
||||||
|
{
|
||||||
|
LOG_ERROR(GENERAL, "RtlAddFunctionTable() failed! Error %u", GetLastError());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return RTDyldMemoryManager::registerEHFrames(addr, load_addr, size);
|
return RTDyldMemoryManager::registerEHFrames(addr, load_addr, size);
|
||||||
}
|
}
|
||||||
|
@ -241,6 +256,36 @@ struct EventListener final : llvm::JITEventListener
|
||||||
const llvm::StringRef elf = obj.getData();
|
const llvm::StringRef elf = obj.getData();
|
||||||
fs::file(path, fs::rewrite).write(elf.data(), elf.size());
|
fs::file(path, fs::rewrite).write(elf.data(), elf.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
for (auto it = obj.section_begin(), end = obj.section_end(); it != end; ++it)
|
||||||
|
{
|
||||||
|
llvm::StringRef name;
|
||||||
|
it->getName(name);
|
||||||
|
|
||||||
|
if (name == ".pdata")
|
||||||
|
{
|
||||||
|
llvm::StringRef data;
|
||||||
|
it->getContents(data);
|
||||||
|
|
||||||
|
std::vector<RUNTIME_FUNCTION> rfs(data.size() / sizeof(RUNTIME_FUNCTION));
|
||||||
|
|
||||||
|
auto offsets = reinterpret_cast<DWORD*>(rfs.data());
|
||||||
|
|
||||||
|
// Initialize .pdata section using relocation info
|
||||||
|
for (auto ri = it->relocation_begin(), end = it->relocation_end(); ri != end; ++ri)
|
||||||
|
{
|
||||||
|
if (ri->getType() == 3 /*R_X86_64_GOT32*/)
|
||||||
|
{
|
||||||
|
const u64 value = *reinterpret_cast<const DWORD*>(data.data() + ri->getOffset());
|
||||||
|
offsets[ri->getOffset() / sizeof(DWORD)] = static_cast<DWORD>(value + ri->getSymbol()->getAddress().get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s_unwind.emplace_back(std::move(rfs));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -250,8 +295,6 @@ jit_compiler::jit_compiler(std::unordered_map<std::string, std::uintptr_t> init_
|
||||||
: m_link(std::move(init_linkage_info))
|
: m_link(std::move(init_linkage_info))
|
||||||
, m_cpu(std::move(_cpu))
|
, m_cpu(std::move(_cpu))
|
||||||
{
|
{
|
||||||
verify(HERE), s_memory;
|
|
||||||
|
|
||||||
// Initialization
|
// Initialization
|
||||||
llvm::InitializeNativeTarget();
|
llvm::InitializeNativeTarget();
|
||||||
llvm::InitializeNativeTargetAsmPrinter();
|
llvm::InitializeNativeTargetAsmPrinter();
|
||||||
|
@ -282,7 +325,6 @@ jit_compiler::jit_compiler(std::unordered_map<std::string, std::uintptr_t> init_
|
||||||
fmt::throw_exception("LLVM: Failed to create ExecutionEngine: %s", result);
|
fmt::throw_exception("LLVM: Failed to create ExecutionEngine: %s", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_engine->setProcessAllSections(true); // ???
|
|
||||||
m_engine->RegisterJITEventListener(&s_listener);
|
m_engine->RegisterJITEventListener(&s_listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,8 +350,6 @@ void jit_compiler::load(std::unique_ptr<llvm::Module> module, std::unique_ptr<ll
|
||||||
m_map[name] = m_engine->getFunctionAddress(name);
|
m_map[name] = m_engine->getFunctionAddress(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
init();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void jit_compiler::make(std::unique_ptr<llvm::Module> module, std::string path)
|
void jit_compiler::make(std::unique_ptr<llvm::Module> module, std::string path)
|
||||||
|
@ -336,74 +376,6 @@ void jit_compiler::make(std::unique_ptr<llvm::Module> module, std::string path)
|
||||||
// Delete IR to lower memory consumption
|
// Delete IR to lower memory consumption
|
||||||
func.deleteBody();
|
func.deleteBody();
|
||||||
}
|
}
|
||||||
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
void jit_compiler::init()
|
|
||||||
{
|
|
||||||
#ifdef _WIN32
|
|
||||||
// Register .xdata UNWIND_INFO (.pdata section is empty for some reason)
|
|
||||||
std::set<u64> func_set;
|
|
||||||
|
|
||||||
for (const auto& pair : m_map)
|
|
||||||
{
|
|
||||||
func_set.emplace(pair.second);
|
|
||||||
}
|
|
||||||
|
|
||||||
const u64 base = (u64)s_memory;
|
|
||||||
const u8* bits = s_unwind_info;
|
|
||||||
|
|
||||||
std::vector<RUNTIME_FUNCTION> unwind;
|
|
||||||
unwind.reserve(m_map.size());
|
|
||||||
|
|
||||||
for (const u64 addr : func_set)
|
|
||||||
{
|
|
||||||
// Find next function address
|
|
||||||
const auto _next = func_set.upper_bound(addr);
|
|
||||||
const u64 next = _next != func_set.end() ? *_next : (u64)s_code_addr + s_code_size;
|
|
||||||
|
|
||||||
// Generate RUNTIME_FUNCTION record
|
|
||||||
RUNTIME_FUNCTION uw;
|
|
||||||
uw.BeginAddress = static_cast<u32>(addr - base);
|
|
||||||
uw.EndAddress = static_cast<u32>(next - base);
|
|
||||||
uw.UnwindData = static_cast<u32>((u64)bits - base);
|
|
||||||
unwind.emplace_back(uw);
|
|
||||||
|
|
||||||
// Parse .xdata UNWIND_INFO record
|
|
||||||
const u8 flags = *bits++; // Version and flags
|
|
||||||
const u8 prolog = *bits++; // Size of prolog
|
|
||||||
const u8 count = *bits++; // Count of unwind codes
|
|
||||||
const u8 frame = *bits++; // Frame Reg + Off
|
|
||||||
bits += ::align(std::max<u8>(1, count), 2) * sizeof(u16); // UNWIND_CODE array
|
|
||||||
|
|
||||||
if (flags != 1)
|
|
||||||
{
|
|
||||||
// Can't happen for trivial code
|
|
||||||
LOG_ERROR(GENERAL, "LLVM: unsupported UNWIND_INFO version/flags (0x%02x)", flags);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_TRACE(GENERAL, "LLVM: .xdata at 0x%llx: function 0x%x..0x%x: p0x%02x, c0x%02x, f0x%02x", uw.UnwindData + base, uw.BeginAddress + base, uw.EndAddress + base, prolog, count, frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s_unwind_info + s_unwind_size != bits)
|
|
||||||
{
|
|
||||||
LOG_ERROR(GENERAL, "LLVM: .xdata analysis failed! (%p != %p)", s_unwind_info + s_unwind_size, bits);
|
|
||||||
}
|
|
||||||
else if (!RtlAddFunctionTable(unwind.data(), (DWORD)unwind.size(), base))
|
|
||||||
{
|
|
||||||
LOG_ERROR(GENERAL, "RtlAddFunctionTable(%p) failed! Error %u", s_unwind_info, GetLastError());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG_NOTICE(GENERAL, "LLVM: UNWIND_INFO registered (%p, size=0x%llx)", s_unwind_info, s_unwind_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
s_unwind.emplace_back(std::move(unwind));
|
|
||||||
#else
|
|
||||||
// TODO: register EH frames if necessary
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jit_compiler::~jit_compiler()
|
jit_compiler::~jit_compiler()
|
||||||
|
|
|
@ -37,9 +37,6 @@ class jit_compiler final
|
||||||
// Arch
|
// Arch
|
||||||
std::string m_cpu;
|
std::string m_cpu;
|
||||||
|
|
||||||
// Internal
|
|
||||||
void init();
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
jit_compiler(std::unordered_map<std::string, std::uintptr_t>, std::string _cpu);
|
jit_compiler(std::unordered_map<std::string, std::uintptr_t>, std::string _cpu);
|
||||||
~jit_compiler();
|
~jit_compiler();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue