Backpatch function addresses.
This commit is contained in:
parent
c1812406f5
commit
c06526e5df
|
@ -231,16 +231,53 @@ void X64Emitter::UnimplementedInstr(const hir::Instr* i) {
|
||||||
XEASSERTALWAYS();
|
XEASSERTALWAYS();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Total size of ResolveFunctionSymbol call site in bytes.
|
||||||
|
// Used to overwrite it with nops as needed.
|
||||||
|
const size_t TOTAL_RESOLVE_SIZE = 27;
|
||||||
|
const size_t ASM_OFFSET = 2 + 2 + 8 + 2 + 8;
|
||||||
|
|
||||||
|
// Length Assembly Byte Sequence
|
||||||
|
// =================================================================================
|
||||||
|
// 2 bytes 66 NOP 66 90H
|
||||||
|
// 3 bytes NOP DWORD ptr [EAX] 0F 1F 00H
|
||||||
|
// 4 bytes NOP DWORD ptr [EAX + 00H] 0F 1F 40 00H
|
||||||
|
// 5 bytes NOP DWORD ptr [EAX + EAX*1 + 00H] 0F 1F 44 00 00H
|
||||||
|
// 6 bytes 66 NOP DWORD ptr [EAX + EAX*1 + 00H] 66 0F 1F 44 00 00H
|
||||||
|
// 7 bytes NOP DWORD ptr [EAX + 00000000H] 0F 1F 80 00 00 00 00H
|
||||||
|
// 8 bytes NOP DWORD ptr [EAX + EAX*1 + 00000000H] 0F 1F 84 00 00 00 00 00H
|
||||||
|
// 9 bytes 66 NOP DWORD ptr [EAX + EAX*1 + 00000000H] 66 0F 1F 84 00 00 00 00 00H
|
||||||
|
|
||||||
uint64_t ResolveFunctionSymbol(void* raw_context, uint64_t symbol_info_ptr) {
|
uint64_t ResolveFunctionSymbol(void* raw_context, uint64_t symbol_info_ptr) {
|
||||||
// TODO(benvanik): generate this thunk at runtime? or a shim?
|
// TODO(benvanik): generate this thunk at runtime? or a shim?
|
||||||
auto thread_state = *reinterpret_cast<ThreadState**>(raw_context);
|
auto thread_state = *reinterpret_cast<ThreadState**>(raw_context);
|
||||||
auto symbol_info = reinterpret_cast<FunctionInfo*>(symbol_info_ptr);
|
auto symbol_info = reinterpret_cast<FunctionInfo*>(symbol_info_ptr);
|
||||||
|
|
||||||
|
// Resolve function. This will demand compile as required.
|
||||||
Function* fn = NULL;
|
Function* fn = NULL;
|
||||||
thread_state->runtime()->ResolveFunction(symbol_info->address(), &fn);
|
thread_state->runtime()->ResolveFunction(symbol_info->address(), &fn);
|
||||||
XEASSERTNOTNULL(fn);
|
XEASSERTNOTNULL(fn);
|
||||||
auto x64_fn = static_cast<X64Function*>(fn);
|
auto x64_fn = static_cast<X64Function*>(fn);
|
||||||
return reinterpret_cast<uint64_t>(x64_fn->machine_code());
|
uint64_t addr = reinterpret_cast<uint64_t>(x64_fn->machine_code());
|
||||||
|
|
||||||
|
// Overwrite the call site.
|
||||||
|
// The return address points to ReloadRCX work after the call.
|
||||||
|
uint64_t return_address = reinterpret_cast<uint64_t>(_ReturnAddress());
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
struct Asm {
|
||||||
|
uint16_t mov_rax;
|
||||||
|
uint64_t rax_constant;
|
||||||
|
uint16_t mov_rdx;
|
||||||
|
uint64_t rdx_constant;
|
||||||
|
uint16_t call_rax;
|
||||||
|
uint8_t mov_rcx[5];
|
||||||
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
Asm* code = reinterpret_cast<Asm*>(return_address - ASM_OFFSET);
|
||||||
|
code->rax_constant = addr;
|
||||||
|
code->call_rax = 0x9066;
|
||||||
|
|
||||||
|
// We need to return the target in rax so that it gets called.
|
||||||
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void X64Emitter::Call(const hir::Instr* instr, runtime::FunctionInfo* symbol_info) {
|
void X64Emitter::Call(const hir::Instr* instr, runtime::FunctionInfo* symbol_info) {
|
||||||
|
@ -250,7 +287,18 @@ void X64Emitter::Call(const hir::Instr* instr, runtime::FunctionInfo* symbol_inf
|
||||||
if (fn) {
|
if (fn) {
|
||||||
mov(rax, reinterpret_cast<uint64_t>(fn->machine_code()));
|
mov(rax, reinterpret_cast<uint64_t>(fn->machine_code()));
|
||||||
} else {
|
} else {
|
||||||
CallNative(ResolveFunctionSymbol, reinterpret_cast<uint64_t>(symbol_info));
|
size_t start = getSize();
|
||||||
|
// 2b + 8b constant
|
||||||
|
mov(rax, reinterpret_cast<uint64_t>(ResolveFunctionSymbol));
|
||||||
|
// 2b + 8b constant
|
||||||
|
mov(rdx, reinterpret_cast<uint64_t>(symbol_info));
|
||||||
|
// 2b
|
||||||
|
call(rax);
|
||||||
|
// 5b
|
||||||
|
ReloadECX();
|
||||||
|
size_t total_size = getSize() - start;
|
||||||
|
XEASSERT(total_size == TOTAL_RESOLVE_SIZE);
|
||||||
|
// EDX overwritten, don't bother reloading.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actually jump/call to rax.
|
// Actually jump/call to rax.
|
||||||
|
|
|
@ -1321,8 +1321,6 @@ int D3D11GraphicsDriver::FetchTexture1D(
|
||||||
}
|
}
|
||||||
|
|
||||||
XEFORCEINLINE void TextureSwap(uint8_t* dest, const uint8_t* src, uint32_t pitch, XE_GPU_ENDIAN endianness) {
|
XEFORCEINLINE void TextureSwap(uint8_t* dest, const uint8_t* src, uint32_t pitch, XE_GPU_ENDIAN endianness) {
|
||||||
SCOPE_profile_cpu_f("gpu");
|
|
||||||
|
|
||||||
switch (endianness) {
|
switch (endianness) {
|
||||||
case XE_GPU_ENDIAN_8IN16:
|
case XE_GPU_ENDIAN_8IN16:
|
||||||
for (uint32_t i = 0; i < pitch; i += 2, src += 2, dest += 2) {
|
for (uint32_t i = 0; i < pitch; i += 2, src += 2, dest += 2) {
|
||||||
|
|
Loading…
Reference in New Issue