[x64] Fix up unwind info for emitted functions.
- [x64] Track size of code within emitted functions (prolog, body, epilog). - [x64] Don't use hardcoded prolog size in generated unwind info. - [x64] Update URLs to MSDN documentation on UNWIND_INFO/UNWIND_CODE.
This commit is contained in:
parent
918a7d4365
commit
0dc4a13db3
|
@ -407,13 +407,25 @@ HostToGuestThunk X64ThunkEmitter::EmitHostToGuestThunk() {
|
||||||
// rdx = arg0 (context)
|
// rdx = arg0 (context)
|
||||||
// r8 = arg1 (guest return address)
|
// r8 = arg1 (guest return address)
|
||||||
|
|
||||||
|
struct _code_offsets {
|
||||||
|
size_t prolog;
|
||||||
|
size_t body;
|
||||||
|
size_t epilog;
|
||||||
|
size_t tail;
|
||||||
|
} code_offsets = {};
|
||||||
|
|
||||||
const size_t stack_size = StackLayout::THUNK_STACK_SIZE;
|
const size_t stack_size = StackLayout::THUNK_STACK_SIZE;
|
||||||
|
|
||||||
|
code_offsets.prolog = getSize();
|
||||||
|
|
||||||
// rsp + 0 = return address
|
// rsp + 0 = return address
|
||||||
mov(qword[rsp + 8 * 3], r8);
|
mov(qword[rsp + 8 * 3], r8);
|
||||||
mov(qword[rsp + 8 * 2], rdx);
|
mov(qword[rsp + 8 * 2], rdx);
|
||||||
mov(qword[rsp + 8 * 1], rcx);
|
mov(qword[rsp + 8 * 1], rcx);
|
||||||
sub(rsp, stack_size);
|
sub(rsp, stack_size);
|
||||||
|
|
||||||
|
code_offsets.body = getSize();
|
||||||
|
|
||||||
// Save nonvolatile registers.
|
// Save nonvolatile registers.
|
||||||
EmitSaveNonvolatileRegs();
|
EmitSaveNonvolatileRegs();
|
||||||
|
|
||||||
|
@ -424,13 +436,26 @@ HostToGuestThunk X64ThunkEmitter::EmitHostToGuestThunk() {
|
||||||
|
|
||||||
EmitLoadNonvolatileRegs();
|
EmitLoadNonvolatileRegs();
|
||||||
|
|
||||||
|
code_offsets.epilog = getSize();
|
||||||
|
|
||||||
add(rsp, stack_size);
|
add(rsp, stack_size);
|
||||||
mov(rcx, qword[rsp + 8 * 1]);
|
mov(rcx, qword[rsp + 8 * 1]);
|
||||||
mov(rdx, qword[rsp + 8 * 2]);
|
mov(rdx, qword[rsp + 8 * 2]);
|
||||||
mov(r8, qword[rsp + 8 * 3]);
|
mov(r8, qword[rsp + 8 * 3]);
|
||||||
ret();
|
ret();
|
||||||
|
|
||||||
void* fn = Emplace(stack_size);
|
code_offsets.tail = getSize();
|
||||||
|
|
||||||
|
assert_zero(code_offsets.prolog);
|
||||||
|
EmitFunctionInfo func_info = {};
|
||||||
|
func_info.code_size.total = getSize();
|
||||||
|
func_info.code_size.prolog = code_offsets.body - code_offsets.prolog;
|
||||||
|
func_info.code_size.body = code_offsets.epilog - code_offsets.body;
|
||||||
|
func_info.code_size.epilog = code_offsets.tail - code_offsets.epilog;
|
||||||
|
func_info.code_size.tail = getSize() - code_offsets.tail;
|
||||||
|
func_info.stack_size = stack_size;
|
||||||
|
|
||||||
|
void* fn = Emplace(func_info);
|
||||||
return (HostToGuestThunk)fn;
|
return (HostToGuestThunk)fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -440,10 +465,22 @@ GuestToHostThunk X64ThunkEmitter::EmitGuestToHostThunk() {
|
||||||
// r8 = arg1
|
// r8 = arg1
|
||||||
// r9 = arg2
|
// r9 = arg2
|
||||||
|
|
||||||
|
struct _code_offsets {
|
||||||
|
size_t prolog;
|
||||||
|
size_t body;
|
||||||
|
size_t epilog;
|
||||||
|
size_t tail;
|
||||||
|
} code_offsets = {};
|
||||||
|
|
||||||
const size_t stack_size = StackLayout::THUNK_STACK_SIZE;
|
const size_t stack_size = StackLayout::THUNK_STACK_SIZE;
|
||||||
|
|
||||||
|
code_offsets.prolog = getSize();
|
||||||
|
|
||||||
// rsp + 0 = return address
|
// rsp + 0 = return address
|
||||||
sub(rsp, stack_size);
|
sub(rsp, stack_size);
|
||||||
|
|
||||||
|
code_offsets.body = getSize();
|
||||||
|
|
||||||
// Save off volatile registers.
|
// Save off volatile registers.
|
||||||
EmitSaveVolatileRegs();
|
EmitSaveVolatileRegs();
|
||||||
|
|
||||||
|
@ -453,10 +490,23 @@ GuestToHostThunk X64ThunkEmitter::EmitGuestToHostThunk() {
|
||||||
|
|
||||||
EmitLoadVolatileRegs();
|
EmitLoadVolatileRegs();
|
||||||
|
|
||||||
|
code_offsets.epilog = getSize();
|
||||||
|
|
||||||
add(rsp, stack_size);
|
add(rsp, stack_size);
|
||||||
ret();
|
ret();
|
||||||
|
|
||||||
void* fn = Emplace(stack_size);
|
code_offsets.tail = getSize();
|
||||||
|
|
||||||
|
assert_zero(code_offsets.prolog);
|
||||||
|
EmitFunctionInfo func_info = {};
|
||||||
|
func_info.code_size.total = getSize();
|
||||||
|
func_info.code_size.prolog = code_offsets.body - code_offsets.prolog;
|
||||||
|
func_info.code_size.body = code_offsets.epilog - code_offsets.body;
|
||||||
|
func_info.code_size.epilog = code_offsets.tail - code_offsets.epilog;
|
||||||
|
func_info.code_size.tail = getSize() - code_offsets.tail;
|
||||||
|
func_info.stack_size = stack_size;
|
||||||
|
|
||||||
|
void* fn = Emplace(func_info);
|
||||||
return (GuestToHostThunk)fn;
|
return (GuestToHostThunk)fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -466,11 +516,23 @@ extern "C" uint64_t ResolveFunction(void* raw_context, uint32_t target_address);
|
||||||
ResolveFunctionThunk X64ThunkEmitter::EmitResolveFunctionThunk() {
|
ResolveFunctionThunk X64ThunkEmitter::EmitResolveFunctionThunk() {
|
||||||
// ebx = target PPC address
|
// ebx = target PPC address
|
||||||
// rcx = context
|
// rcx = context
|
||||||
|
|
||||||
|
struct _code_offsets {
|
||||||
|
size_t prolog;
|
||||||
|
size_t body;
|
||||||
|
size_t epilog;
|
||||||
|
size_t tail;
|
||||||
|
} code_offsets = {};
|
||||||
|
|
||||||
const size_t stack_size = StackLayout::THUNK_STACK_SIZE;
|
const size_t stack_size = StackLayout::THUNK_STACK_SIZE;
|
||||||
|
|
||||||
|
code_offsets.prolog = getSize();
|
||||||
|
|
||||||
// rsp + 0 = return address
|
// rsp + 0 = return address
|
||||||
sub(rsp, stack_size);
|
sub(rsp, stack_size);
|
||||||
|
|
||||||
|
code_offsets.body = getSize();
|
||||||
|
|
||||||
// Save volatile registers
|
// Save volatile registers
|
||||||
EmitSaveVolatileRegs();
|
EmitSaveVolatileRegs();
|
||||||
|
|
||||||
|
@ -481,10 +543,23 @@ ResolveFunctionThunk X64ThunkEmitter::EmitResolveFunctionThunk() {
|
||||||
|
|
||||||
EmitLoadVolatileRegs();
|
EmitLoadVolatileRegs();
|
||||||
|
|
||||||
|
code_offsets.epilog = getSize();
|
||||||
|
|
||||||
add(rsp, stack_size);
|
add(rsp, stack_size);
|
||||||
jmp(rax);
|
jmp(rax);
|
||||||
|
|
||||||
void* fn = Emplace(stack_size);
|
code_offsets.tail = getSize();
|
||||||
|
|
||||||
|
assert_zero(code_offsets.prolog);
|
||||||
|
EmitFunctionInfo func_info = {};
|
||||||
|
func_info.code_size.total = getSize();
|
||||||
|
func_info.code_size.prolog = code_offsets.body - code_offsets.prolog;
|
||||||
|
func_info.code_size.body = code_offsets.epilog - code_offsets.body;
|
||||||
|
func_info.code_size.epilog = code_offsets.tail - code_offsets.epilog;
|
||||||
|
func_info.code_size.tail = getSize() - code_offsets.tail;
|
||||||
|
func_info.stack_size = stack_size;
|
||||||
|
|
||||||
|
void* fn = Emplace(func_info);
|
||||||
return (ResolveFunctionThunk)fn;
|
return (ResolveFunctionThunk)fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -125,15 +125,14 @@ void X64CodeCache::CommitExecutableRange(uint32_t guest_low,
|
||||||
}
|
}
|
||||||
|
|
||||||
void* X64CodeCache::PlaceHostCode(uint32_t guest_address, void* machine_code,
|
void* X64CodeCache::PlaceHostCode(uint32_t guest_address, void* machine_code,
|
||||||
size_t code_size, size_t stack_size) {
|
const EmitFunctionInfo& func_info) {
|
||||||
// Same for now. We may use different pools or whatnot later on, like when
|
// Same for now. We may use different pools or whatnot later on, like when
|
||||||
// we only want to place guest code in a serialized cache on disk.
|
// we only want to place guest code in a serialized cache on disk.
|
||||||
return PlaceGuestCode(guest_address, machine_code, code_size, stack_size,
|
return PlaceGuestCode(guest_address, machine_code, func_info, nullptr);
|
||||||
nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void* X64CodeCache::PlaceGuestCode(uint32_t guest_address, void* machine_code,
|
void* X64CodeCache::PlaceGuestCode(uint32_t guest_address, void* machine_code,
|
||||||
size_t code_size, size_t stack_size,
|
const EmitFunctionInfo& func_info,
|
||||||
GuestFunction* function_info) {
|
GuestFunction* function_info) {
|
||||||
// Hold a lock while we bump the pointers up. This is important as the
|
// Hold a lock while we bump the pointers up. This is important as the
|
||||||
// unwind table requires entries AND code to be sorted in order.
|
// unwind table requires entries AND code to be sorted in order.
|
||||||
|
@ -149,7 +148,7 @@ void* X64CodeCache::PlaceGuestCode(uint32_t guest_address, void* machine_code,
|
||||||
// Reserve code.
|
// Reserve code.
|
||||||
// Always move the code to land on 16b alignment.
|
// Always move the code to land on 16b alignment.
|
||||||
code_address = generated_code_base_ + generated_code_offset_;
|
code_address = generated_code_base_ + generated_code_offset_;
|
||||||
generated_code_offset_ += xe::round_up(code_size, 16);
|
generated_code_offset_ += xe::round_up(func_info.code_size.total, 16);
|
||||||
|
|
||||||
// Reserve unwind info.
|
// Reserve unwind info.
|
||||||
// We go on the high size of the unwind info as we don't know how big we
|
// We go on the high size of the unwind info as we don't know how big we
|
||||||
|
@ -187,15 +186,17 @@ void* X64CodeCache::PlaceGuestCode(uint32_t guest_address, void* machine_code,
|
||||||
old_commit_mark, new_commit_mark));
|
old_commit_mark, new_commit_mark));
|
||||||
|
|
||||||
// Copy code.
|
// Copy code.
|
||||||
std::memcpy(code_address, machine_code, code_size);
|
std::memcpy(code_address, machine_code, func_info.code_size.total);
|
||||||
|
|
||||||
// Fill unused slots with 0xCC
|
// Fill unused slots with 0xCC
|
||||||
std::memset(
|
std::memset(
|
||||||
code_address + code_size, 0xCC,
|
code_address + func_info.code_size.total, 0xCC,
|
||||||
xe::round_up(code_size + unwind_reservation.data_size, 16) - code_size);
|
xe::round_up(func_info.code_size.total + unwind_reservation.data_size,
|
||||||
|
16) -
|
||||||
|
func_info.code_size.total);
|
||||||
|
|
||||||
// Notify subclasses of placed code.
|
// Notify subclasses of placed code.
|
||||||
PlaceCode(guest_address, machine_code, code_size, stack_size, code_address,
|
PlaceCode(guest_address, machine_code, func_info, code_address,
|
||||||
unwind_reservation);
|
unwind_reservation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,17 @@ namespace cpu {
|
||||||
namespace backend {
|
namespace backend {
|
||||||
namespace x64 {
|
namespace x64 {
|
||||||
|
|
||||||
|
struct EmitFunctionInfo {
|
||||||
|
struct _code_size {
|
||||||
|
size_t prolog;
|
||||||
|
size_t body;
|
||||||
|
size_t epilog;
|
||||||
|
size_t tail;
|
||||||
|
size_t total;
|
||||||
|
} code_size;
|
||||||
|
size_t stack_size;
|
||||||
|
};
|
||||||
|
|
||||||
class X64CodeCache : public CodeCache {
|
class X64CodeCache : public CodeCache {
|
||||||
public:
|
public:
|
||||||
~X64CodeCache() override;
|
~X64CodeCache() override;
|
||||||
|
@ -48,9 +59,9 @@ class X64CodeCache : public CodeCache {
|
||||||
void CommitExecutableRange(uint32_t guest_low, uint32_t guest_high);
|
void CommitExecutableRange(uint32_t guest_low, uint32_t guest_high);
|
||||||
|
|
||||||
void* PlaceHostCode(uint32_t guest_address, void* machine_code,
|
void* PlaceHostCode(uint32_t guest_address, void* machine_code,
|
||||||
size_t code_size, size_t stack_size);
|
const EmitFunctionInfo& func_info);
|
||||||
void* PlaceGuestCode(uint32_t guest_address, void* machine_code,
|
void* PlaceGuestCode(uint32_t guest_address, void* machine_code,
|
||||||
size_t code_size, size_t stack_size,
|
const EmitFunctionInfo& func_info,
|
||||||
GuestFunction* function_info);
|
GuestFunction* function_info);
|
||||||
uint32_t PlaceData(const void* data, size_t length);
|
uint32_t PlaceData(const void* data, size_t length);
|
||||||
|
|
||||||
|
@ -84,8 +95,7 @@ class X64CodeCache : public CodeCache {
|
||||||
return UnwindReservation();
|
return UnwindReservation();
|
||||||
}
|
}
|
||||||
virtual void PlaceCode(uint32_t guest_address, void* machine_code,
|
virtual void PlaceCode(uint32_t guest_address, void* machine_code,
|
||||||
size_t code_size, size_t stack_size,
|
const EmitFunctionInfo& func_info, void* code_address,
|
||||||
void* code_address,
|
|
||||||
UnwindReservation unwind_reservation) {}
|
UnwindReservation unwind_reservation) {}
|
||||||
|
|
||||||
std::wstring file_name_;
|
std::wstring file_name_;
|
||||||
|
|
|
@ -112,13 +112,13 @@ class Win32X64CodeCache : public X64CodeCache {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
UnwindReservation RequestUnwindReservation(uint8_t* entry_address) override;
|
UnwindReservation RequestUnwindReservation(uint8_t* entry_address) override;
|
||||||
void PlaceCode(uint32_t guest_address, void* machine_code, size_t code_size,
|
void PlaceCode(uint32_t guest_address, void* machine_code,
|
||||||
size_t stack_size, void* code_address,
|
const EmitFunctionInfo& func_info, void* code_address,
|
||||||
UnwindReservation unwind_reservation) override;
|
UnwindReservation unwind_reservation) override;
|
||||||
|
|
||||||
void InitializeUnwindEntry(uint8_t* unwind_entry_address,
|
void InitializeUnwindEntry(uint8_t* unwind_entry_address,
|
||||||
size_t unwind_table_slot, void* code_address,
|
size_t unwind_table_slot, void* code_address,
|
||||||
size_t code_size, size_t stack_size);
|
const EmitFunctionInfo& func_info);
|
||||||
|
|
||||||
// Growable function table system handle.
|
// Growable function table system handle.
|
||||||
void* unwind_table_handle_ = nullptr;
|
void* unwind_table_handle_ = nullptr;
|
||||||
|
@ -222,13 +222,12 @@ Win32X64CodeCache::RequestUnwindReservation(uint8_t* entry_address) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Win32X64CodeCache::PlaceCode(uint32_t guest_address, void* machine_code,
|
void Win32X64CodeCache::PlaceCode(uint32_t guest_address, void* machine_code,
|
||||||
size_t code_size, size_t stack_size,
|
const EmitFunctionInfo& func_info,
|
||||||
void* code_address,
|
void* code_address,
|
||||||
UnwindReservation unwind_reservation) {
|
UnwindReservation unwind_reservation) {
|
||||||
// Add unwind info.
|
// Add unwind info.
|
||||||
InitializeUnwindEntry(unwind_reservation.entry_address,
|
InitializeUnwindEntry(unwind_reservation.entry_address,
|
||||||
unwind_reservation.table_slot, code_address, code_size,
|
unwind_reservation.table_slot, code_address, func_info);
|
||||||
stack_size);
|
|
||||||
|
|
||||||
if (supports_growable_table_) {
|
if (supports_growable_table_) {
|
||||||
// Notify that the unwind table has grown.
|
// Notify that the unwind table has grown.
|
||||||
|
@ -237,29 +236,29 @@ void Win32X64CodeCache::PlaceCode(uint32_t guest_address, void* machine_code,
|
||||||
}
|
}
|
||||||
|
|
||||||
// This isn't needed on x64 (probably), but is convention.
|
// This isn't needed on x64 (probably), but is convention.
|
||||||
FlushInstructionCache(GetCurrentProcess(), code_address, code_size);
|
FlushInstructionCache(GetCurrentProcess(), code_address,
|
||||||
|
func_info.code_size.total);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Win32X64CodeCache::InitializeUnwindEntry(uint8_t* unwind_entry_address,
|
void Win32X64CodeCache::InitializeUnwindEntry(
|
||||||
size_t unwind_table_slot,
|
uint8_t* unwind_entry_address, size_t unwind_table_slot, void* code_address,
|
||||||
void* code_address,
|
const EmitFunctionInfo& func_info) {
|
||||||
size_t code_size,
|
|
||||||
size_t stack_size) {
|
|
||||||
auto unwind_info = reinterpret_cast<UNWIND_INFO*>(unwind_entry_address);
|
auto unwind_info = reinterpret_cast<UNWIND_INFO*>(unwind_entry_address);
|
||||||
UNWIND_CODE* unwind_code = nullptr;
|
UNWIND_CODE* unwind_code = nullptr;
|
||||||
|
|
||||||
if (!stack_size) {
|
assert_true(func_info.code_size.prolog < 256); // needs to fit into a uint8_t
|
||||||
// https://msdn.microsoft.com/en-us/library/ddssxxy8.aspx
|
auto prolog_size = static_cast<uint8_t>(func_info.code_size.prolog);
|
||||||
|
|
||||||
|
if (!func_info.stack_size) {
|
||||||
|
// https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64#struct-unwind_info
|
||||||
unwind_info->Version = 1;
|
unwind_info->Version = 1;
|
||||||
unwind_info->Flags = 0;
|
unwind_info->Flags = 0;
|
||||||
unwind_info->SizeOfProlog = 0;
|
unwind_info->SizeOfProlog = prolog_size;
|
||||||
unwind_info->CountOfCodes = 0;
|
unwind_info->CountOfCodes = 0;
|
||||||
unwind_info->FrameRegister = 0;
|
unwind_info->FrameRegister = 0;
|
||||||
unwind_info->FrameOffset = 0;
|
unwind_info->FrameOffset = 0;
|
||||||
} else if (stack_size <= 128) {
|
} else if (func_info.stack_size <= 128) {
|
||||||
uint8_t prolog_size = 4;
|
// https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64#struct-unwind_info
|
||||||
|
|
||||||
// https://msdn.microsoft.com/en-us/library/ddssxxy8.aspx
|
|
||||||
unwind_info->Version = 1;
|
unwind_info->Version = 1;
|
||||||
unwind_info->Flags = 0;
|
unwind_info->Flags = 0;
|
||||||
unwind_info->SizeOfProlog = prolog_size;
|
unwind_info->SizeOfProlog = prolog_size;
|
||||||
|
@ -267,17 +266,16 @@ void Win32X64CodeCache::InitializeUnwindEntry(uint8_t* unwind_entry_address,
|
||||||
unwind_info->FrameRegister = 0;
|
unwind_info->FrameRegister = 0;
|
||||||
unwind_info->FrameOffset = 0;
|
unwind_info->FrameOffset = 0;
|
||||||
|
|
||||||
// https://msdn.microsoft.com/en-us/library/ck9asaa9.aspx
|
// https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64#struct-unwind_code
|
||||||
unwind_code = &unwind_info->UnwindCode[unwind_info->CountOfCodes++];
|
unwind_code = &unwind_info->UnwindCode[unwind_info->CountOfCodes++];
|
||||||
unwind_code->CodeOffset =
|
unwind_code->CodeOffset =
|
||||||
14; // end of instruction + 1 == offset of next instruction
|
14; // end of instruction + 1 == offset of next instruction
|
||||||
unwind_code->UnwindOp = UWOP_ALLOC_SMALL;
|
unwind_code->UnwindOp = UWOP_ALLOC_SMALL;
|
||||||
unwind_code->OpInfo = stack_size / 8 - 1;
|
unwind_code->OpInfo = func_info.stack_size / 8 - 1;
|
||||||
} else {
|
} else {
|
||||||
// TODO(benvanik): take as parameters?
|
// TODO(benvanik): take as parameters?
|
||||||
uint8_t prolog_size = 7;
|
|
||||||
|
|
||||||
// https://msdn.microsoft.com/en-us/library/ddssxxy8.aspx
|
// https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64#struct-unwind_info
|
||||||
unwind_info->Version = 1;
|
unwind_info->Version = 1;
|
||||||
unwind_info->Flags = 0;
|
unwind_info->Flags = 0;
|
||||||
unwind_info->SizeOfProlog = prolog_size;
|
unwind_info->SizeOfProlog = prolog_size;
|
||||||
|
@ -285,16 +283,16 @@ void Win32X64CodeCache::InitializeUnwindEntry(uint8_t* unwind_entry_address,
|
||||||
unwind_info->FrameRegister = 0;
|
unwind_info->FrameRegister = 0;
|
||||||
unwind_info->FrameOffset = 0;
|
unwind_info->FrameOffset = 0;
|
||||||
|
|
||||||
// https://msdn.microsoft.com/en-us/library/ck9asaa9.aspx
|
// https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64#struct-unwind_code
|
||||||
unwind_code = &unwind_info->UnwindCode[unwind_info->CountOfCodes++];
|
unwind_code = &unwind_info->UnwindCode[unwind_info->CountOfCodes++];
|
||||||
unwind_code->CodeOffset =
|
unwind_code->CodeOffset =
|
||||||
7; // end of instruction + 1 == offset of next instruction
|
7; // end of instruction + 1 == offset of next instruction
|
||||||
unwind_code->UnwindOp = UWOP_ALLOC_LARGE;
|
unwind_code->UnwindOp = UWOP_ALLOC_LARGE;
|
||||||
unwind_code->OpInfo = 0; // One slot for size
|
unwind_code->OpInfo = 0; // One slot for size
|
||||||
|
|
||||||
assert_true((stack_size / 8) < 65536u);
|
assert_true((func_info.stack_size / 8) < 65536u);
|
||||||
unwind_code = &unwind_info->UnwindCode[unwind_info->CountOfCodes++];
|
unwind_code = &unwind_info->UnwindCode[unwind_info->CountOfCodes++];
|
||||||
unwind_code->FrameOffset = (USHORT)(stack_size) / 8;
|
unwind_code->FrameOffset = (USHORT)(func_info.stack_size) / 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unwind_info->CountOfCodes % 1) {
|
if (unwind_info->CountOfCodes % 1) {
|
||||||
|
@ -307,7 +305,8 @@ void Win32X64CodeCache::InitializeUnwindEntry(uint8_t* unwind_entry_address,
|
||||||
auto& fn_entry = unwind_table_[unwind_table_slot];
|
auto& fn_entry = unwind_table_[unwind_table_slot];
|
||||||
fn_entry.BeginAddress =
|
fn_entry.BeginAddress =
|
||||||
(DWORD)(reinterpret_cast<uint8_t*>(code_address) - generated_code_base_);
|
(DWORD)(reinterpret_cast<uint8_t*>(code_address) - generated_code_base_);
|
||||||
fn_entry.EndAddress = (DWORD)(fn_entry.BeginAddress + code_size);
|
fn_entry.EndAddress =
|
||||||
|
(DWORD)(fn_entry.BeginAddress + func_info.code_size.total);
|
||||||
fn_entry.UnwindData = (DWORD)(unwind_entry_address - generated_code_base_);
|
fn_entry.UnwindData = (DWORD)(unwind_entry_address - generated_code_base_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -102,14 +102,14 @@ bool X64Emitter::Emit(GuestFunction* function, HIRBuilder* builder,
|
||||||
source_map_arena_.Reset();
|
source_map_arena_.Reset();
|
||||||
|
|
||||||
// Fill the generator with code.
|
// Fill the generator with code.
|
||||||
size_t stack_size = 0;
|
EmitFunctionInfo func_info = {};
|
||||||
if (!Emit(builder, &stack_size)) {
|
if (!Emit(builder, func_info)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy the final code to the cache and relocate it.
|
// Copy the final code to the cache and relocate it.
|
||||||
*out_code_size = getSize();
|
*out_code_size = getSize();
|
||||||
*out_code_address = Emplace(stack_size, function);
|
*out_code_address = Emplace(func_info, function);
|
||||||
|
|
||||||
// Stash source map.
|
// Stash source map.
|
||||||
source_map_arena_.CloneContents(out_source_map);
|
source_map_arena_.CloneContents(out_source_map);
|
||||||
|
@ -117,18 +117,20 @@ bool X64Emitter::Emit(GuestFunction* function, HIRBuilder* builder,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* X64Emitter::Emplace(size_t stack_size, GuestFunction* function) {
|
void* X64Emitter::Emplace(const EmitFunctionInfo& func_info,
|
||||||
|
GuestFunction* function) {
|
||||||
// To avoid changing xbyak, we do a switcharoo here.
|
// To avoid changing xbyak, we do a switcharoo here.
|
||||||
// top_ points to the Xbyak buffer, and since we are in AutoGrow mode
|
// top_ points to the Xbyak buffer, and since we are in AutoGrow mode
|
||||||
// it has pending relocations. We copy the top_ to our buffer, swap the
|
// it has pending relocations. We copy the top_ to our buffer, swap the
|
||||||
// pointer, relocate, then return the original scratch pointer for use.
|
// pointer, relocate, then return the original scratch pointer for use.
|
||||||
uint8_t* old_address = top_;
|
uint8_t* old_address = top_;
|
||||||
void* new_address;
|
void* new_address;
|
||||||
|
assert_true(func_info.code_size.total == size_);
|
||||||
if (function) {
|
if (function) {
|
||||||
new_address = code_cache_->PlaceGuestCode(function->address(), top_, size_,
|
new_address = code_cache_->PlaceGuestCode(function->address(), top_,
|
||||||
stack_size, function);
|
func_info, function);
|
||||||
} else {
|
} else {
|
||||||
new_address = code_cache_->PlaceHostCode(0, top_, size_, stack_size);
|
new_address = code_cache_->PlaceHostCode(0, top_, func_info);
|
||||||
}
|
}
|
||||||
top_ = reinterpret_cast<uint8_t*>(new_address);
|
top_ = reinterpret_cast<uint8_t*>(new_address);
|
||||||
ready();
|
ready();
|
||||||
|
@ -137,7 +139,7 @@ void* X64Emitter::Emplace(size_t stack_size, GuestFunction* function) {
|
||||||
return new_address;
|
return new_address;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool X64Emitter::Emit(HIRBuilder* builder, size_t* out_stack_size) {
|
bool X64Emitter::Emit(HIRBuilder* builder, EmitFunctionInfo& func_info) {
|
||||||
Xbyak::Label epilog_label;
|
Xbyak::Label epilog_label;
|
||||||
epilog_label_ = &epilog_label;
|
epilog_label_ = &epilog_label;
|
||||||
|
|
||||||
|
@ -159,6 +161,15 @@ bool X64Emitter::Emit(HIRBuilder* builder, size_t* out_stack_size) {
|
||||||
stack_offset -= StackLayout::GUEST_STACK_SIZE;
|
stack_offset -= StackLayout::GUEST_STACK_SIZE;
|
||||||
stack_offset = xe::align(stack_offset, static_cast<size_t>(16));
|
stack_offset = xe::align(stack_offset, static_cast<size_t>(16));
|
||||||
|
|
||||||
|
struct _code_offsets {
|
||||||
|
size_t prolog;
|
||||||
|
size_t body;
|
||||||
|
size_t epilog;
|
||||||
|
size_t tail;
|
||||||
|
} code_offsets = {};
|
||||||
|
|
||||||
|
code_offsets.prolog = getSize();
|
||||||
|
|
||||||
// Function prolog.
|
// Function prolog.
|
||||||
// Must be 16b aligned.
|
// Must be 16b aligned.
|
||||||
// Windows is very strict about the form of this and the epilog:
|
// Windows is very strict about the form of this and the epilog:
|
||||||
|
@ -168,7 +179,7 @@ bool X64Emitter::Emit(HIRBuilder* builder, size_t* out_stack_size) {
|
||||||
// Adding or changing anything here must be matched!
|
// Adding or changing anything here must be matched!
|
||||||
const size_t stack_size = StackLayout::GUEST_STACK_SIZE + stack_offset;
|
const size_t stack_size = StackLayout::GUEST_STACK_SIZE + stack_offset;
|
||||||
assert_true((stack_size + 8) % 16 == 0);
|
assert_true((stack_size + 8) % 16 == 0);
|
||||||
*out_stack_size = stack_size;
|
func_info.stack_size = stack_size;
|
||||||
stack_size_ = stack_size;
|
stack_size_ = stack_size;
|
||||||
|
|
||||||
sub(rsp, (uint32_t)stack_size);
|
sub(rsp, (uint32_t)stack_size);
|
||||||
|
@ -208,6 +219,8 @@ bool X64Emitter::Emit(HIRBuilder* builder, size_t* out_stack_size) {
|
||||||
mov(GetMembaseReg(),
|
mov(GetMembaseReg(),
|
||||||
qword[GetContextReg() + offsetof(ppc::PPCContext, virtual_membase)]);
|
qword[GetContextReg() + offsetof(ppc::PPCContext, virtual_membase)]);
|
||||||
|
|
||||||
|
code_offsets.body = getSize();
|
||||||
|
|
||||||
// Body.
|
// Body.
|
||||||
auto block = builder->first_block();
|
auto block = builder->first_block();
|
||||||
while (block) {
|
while (block) {
|
||||||
|
@ -236,6 +249,8 @@ bool X64Emitter::Emit(HIRBuilder* builder, size_t* out_stack_size) {
|
||||||
block = block->next;
|
block = block->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
code_offsets.epilog = getSize();
|
||||||
|
|
||||||
// Function epilog.
|
// Function epilog.
|
||||||
L(epilog_label);
|
L(epilog_label);
|
||||||
epilog_label_ = nullptr;
|
epilog_label_ = nullptr;
|
||||||
|
@ -244,6 +259,8 @@ bool X64Emitter::Emit(HIRBuilder* builder, size_t* out_stack_size) {
|
||||||
add(rsp, (uint32_t)stack_size);
|
add(rsp, (uint32_t)stack_size);
|
||||||
ret();
|
ret();
|
||||||
|
|
||||||
|
code_offsets.tail = getSize();
|
||||||
|
|
||||||
if (cvars::emit_source_annotations) {
|
if (cvars::emit_source_annotations) {
|
||||||
nop();
|
nop();
|
||||||
nop();
|
nop();
|
||||||
|
@ -252,6 +269,13 @@ bool X64Emitter::Emit(HIRBuilder* builder, size_t* out_stack_size) {
|
||||||
nop();
|
nop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert_zero(code_offsets.prolog);
|
||||||
|
func_info.code_size.total = getSize();
|
||||||
|
func_info.code_size.prolog = code_offsets.body - code_offsets.prolog;
|
||||||
|
func_info.code_size.body = code_offsets.epilog - code_offsets.body;
|
||||||
|
func_info.code_size.epilog = code_offsets.tail - code_offsets.epilog;
|
||||||
|
func_info.code_size.tail = getSize() - code_offsets.tail;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,8 @@ namespace x64 {
|
||||||
class X64Backend;
|
class X64Backend;
|
||||||
class X64CodeCache;
|
class X64CodeCache;
|
||||||
|
|
||||||
|
struct EmitFunctionInfo;
|
||||||
|
|
||||||
enum RegisterFlags {
|
enum RegisterFlags {
|
||||||
REG_DEST = (1 << 0),
|
REG_DEST = (1 << 0),
|
||||||
REG_ABCD = (1 << 1),
|
REG_ABCD = (1 << 1),
|
||||||
|
@ -222,8 +224,9 @@ class X64Emitter : public Xbyak::CodeGenerator {
|
||||||
size_t stack_size() const { return stack_size_; }
|
size_t stack_size() const { return stack_size_; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void* Emplace(size_t stack_size, GuestFunction* function = nullptr);
|
void* Emplace(const EmitFunctionInfo& func_info,
|
||||||
bool Emit(hir::HIRBuilder* builder, size_t* out_stack_size);
|
GuestFunction* function = nullptr);
|
||||||
|
bool Emit(hir::HIRBuilder* builder, EmitFunctionInfo& func_info);
|
||||||
void EmitGetCurrentThreadId();
|
void EmitGetCurrentThreadId();
|
||||||
void EmitTraceUserCallReturn();
|
void EmitTraceUserCallReturn();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue