Skip to content

Commit ad72168

Browse files
committed
LLVM: load .pdata section
1 parent 4fc8276 commit ad72168

File tree

2 files changed

+51
-82
lines changed

2 files changed

+51
-82
lines changed

Utilities/JIT.cpp

+51-79
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,6 @@ static void* const s_memory = []() -> void*
5454
static u8* s_code_addr;
5555
static u64 s_code_size;
5656

57-
// EH frames
58-
static u8* s_unwind_info;
59-
static u64 s_unwind_size;
60-
6157
#ifdef _WIN32
6258
static std::vector<std::vector<RUNTIME_FUNCTION>> s_unwind; // .pdata
6359
#endif
@@ -193,8 +189,27 @@ struct MemoryManager final : llvm::RTDyldMemoryManager
193189

194190
virtual void registerEHFrames(u8* addr, u64 load_addr, std::size_t size) override
195191
{
196-
s_unwind_info = addr;
197-
s_unwind_size = size;
192+
#ifdef _WIN32
193+
// Use s_memory as a BASE, compute the difference
194+
const u64 code_diff = (u64)s_code_addr - (u64)s_memory;
195+
const u64 unwind_diff = (u64)addr - (u64)s_memory;
196+
197+
// Fix RUNTIME_FUNCTION records (.pdata section)
198+
auto& pdata = s_unwind.back();
199+
200+
for (auto& rf : pdata)
201+
{
202+
rf.BeginAddress += static_cast<DWORD>(code_diff);
203+
rf.EndAddress += static_cast<DWORD>(code_diff);
204+
rf.UnwindData += static_cast<DWORD>(unwind_diff);
205+
}
206+
207+
// Register .xdata UNWIND_INFO structs
208+
if (!RtlAddFunctionTable(pdata.data(), (DWORD)pdata.size(), (u64)s_memory))
209+
{
210+
LOG_ERROR(GENERAL, "RtlAddFunctionTable() failed! Error %u", GetLastError());
211+
}
212+
#endif
198213

199214
return RTDyldMemoryManager::registerEHFrames(addr, load_addr, size);
200215
}
@@ -241,6 +256,36 @@ struct EventListener final : llvm::JITEventListener
241256
const llvm::StringRef elf = obj.getData();
242257
fs::file(path, fs::rewrite).write(elf.data(), elf.size());
243258
}
259+
260+
#ifdef _WIN32
261+
for (auto it = obj.section_begin(), end = obj.section_end(); it != end; ++it)
262+
{
263+
llvm::StringRef name;
264+
it->getName(name);
265+
266+
if (name == ".pdata")
267+
{
268+
llvm::StringRef data;
269+
it->getContents(data);
270+
271+
std::vector<RUNTIME_FUNCTION> rfs(data.size() / sizeof(RUNTIME_FUNCTION));
272+
273+
auto offsets = reinterpret_cast<DWORD*>(rfs.data());
274+
275+
// Initialize .pdata section using relocation info
276+
for (auto ri = it->relocation_begin(), end = it->relocation_end(); ri != end; ++ri)
277+
{
278+
if (ri->getType() == 3 /*R_X86_64_GOT32*/)
279+
{
280+
const u64 value = *reinterpret_cast<const DWORD*>(data.data() + ri->getOffset());
281+
offsets[ri->getOffset() / sizeof(DWORD)] = static_cast<DWORD>(value + ri->getSymbol()->getAddress().get());
282+
}
283+
}
284+
285+
s_unwind.emplace_back(std::move(rfs));
286+
}
287+
}
288+
#endif
244289
}
245290
};
246291

@@ -250,8 +295,6 @@ jit_compiler::jit_compiler(std::unordered_map<std::string, std::uintptr_t> init_
250295
: m_link(std::move(init_linkage_info))
251296
, m_cpu(std::move(_cpu))
252297
{
253-
verify(HERE), s_memory;
254-
255298
// Initialization
256299
llvm::InitializeNativeTarget();
257300
llvm::InitializeNativeTargetAsmPrinter();
@@ -282,7 +325,6 @@ jit_compiler::jit_compiler(std::unordered_map<std::string, std::uintptr_t> init_
282325
fmt::throw_exception("LLVM: Failed to create ExecutionEngine: %s", result);
283326
}
284327

285-
m_engine->setProcessAllSections(true); // ???
286328
m_engine->RegisterJITEventListener(&s_listener);
287329
}
288330

@@ -308,8 +350,6 @@ void jit_compiler::load(std::unique_ptr<llvm::Module> module, std::unique_ptr<ll
308350
m_map[name] = m_engine->getFunctionAddress(name);
309351
}
310352
}
311-
312-
init();
313353
}
314354

315355
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)
336376
// Delete IR to lower memory consumption
337377
func.deleteBody();
338378
}
339-
340-
init();
341-
}
342-
343-
void jit_compiler::init()
344-
{
345-
#ifdef _WIN32
346-
// Register .xdata UNWIND_INFO (.pdata section is empty for some reason)
347-
std::set<u64> func_set;
348-
349-
for (const auto& pair : m_map)
350-
{
351-
func_set.emplace(pair.second);
352-
}
353-
354-
const u64 base = (u64)s_memory;
355-
const u8* bits = s_unwind_info;
356-
357-
std::vector<RUNTIME_FUNCTION> unwind;
358-
unwind.reserve(m_map.size());
359-
360-
for (const u64 addr : func_set)
361-
{
362-
// Find next function address
363-
const auto _next = func_set.upper_bound(addr);
364-
const u64 next = _next != func_set.end() ? *_next : (u64)s_code_addr + s_code_size;
365-
366-
// Generate RUNTIME_FUNCTION record
367-
RUNTIME_FUNCTION uw;
368-
uw.BeginAddress = static_cast<u32>(addr - base);
369-
uw.EndAddress = static_cast<u32>(next - base);
370-
uw.UnwindData = static_cast<u32>((u64)bits - base);
371-
unwind.emplace_back(uw);
372-
373-
// Parse .xdata UNWIND_INFO record
374-
const u8 flags = *bits++; // Version and flags
375-
const u8 prolog = *bits++; // Size of prolog
376-
const u8 count = *bits++; // Count of unwind codes
377-
const u8 frame = *bits++; // Frame Reg + Off
378-
bits += ::align(std::max<u8>(1, count), 2) * sizeof(u16); // UNWIND_CODE array
379-
380-
if (flags != 1)
381-
{
382-
// Can't happen for trivial code
383-
LOG_ERROR(GENERAL, "LLVM: unsupported UNWIND_INFO version/flags (0x%02x)", flags);
384-
break;
385-
}
386-
387-
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);
388-
}
389-
390-
if (s_unwind_info + s_unwind_size != bits)
391-
{
392-
LOG_ERROR(GENERAL, "LLVM: .xdata analysis failed! (%p != %p)", s_unwind_info + s_unwind_size, bits);
393-
}
394-
else if (!RtlAddFunctionTable(unwind.data(), (DWORD)unwind.size(), base))
395-
{
396-
LOG_ERROR(GENERAL, "RtlAddFunctionTable(%p) failed! Error %u", s_unwind_info, GetLastError());
397-
}
398-
else
399-
{
400-
LOG_NOTICE(GENERAL, "LLVM: UNWIND_INFO registered (%p, size=0x%llx)", s_unwind_info, s_unwind_size);
401-
}
402-
403-
s_unwind.emplace_back(std::move(unwind));
404-
#else
405-
// TODO: register EH frames if necessary
406-
#endif
407379
}
408380

409381
jit_compiler::~jit_compiler()

Utilities/JIT.h

-3
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,6 @@ class jit_compiler final
3737
// Arch
3838
std::string m_cpu;
3939

40-
// Internal
41-
void init();
42-
4340
public:
4441
jit_compiler(std::unordered_map<std::string, std::uintptr_t>, std::string _cpu);
4542
~jit_compiler();

0 commit comments

Comments
 (0)