我正在编写一个JIT编译器,它必须从编译的asm代码中调用c ++函数。
我目前只在Windows x64上工作,并实现了微软的调用约定。 (https://msdn.microsoft.com/en-us/library/ms235286.aspx)
它有效,直到它没有。
如果被调用的函数很简单并且只调用简单的函数(使用类似C的子集),它似乎总能工作。 如果被调用函数调用其他函数,例如“std :: cout”,如果它是为Debug编译的,它可以工作,但不适用于发布。 如果被调用的函数调用某些VULKAN函数,它根本不起作用。
jit编译器生成的代码示例:
sub %10 r64(4), imm8(48)
mov %1 r64(0), %6 r64(1)
mov %2 r64(2), m64[%1]
mov %3 r32(1), imm32(5)
mov ST: m64 +40, %2 r64(2)
call m64 <call PrintInt()>
mov %2 r64(2), ST: m64 +40
mov m32[%2] +16, %4 r32(0)
mov %5 r32(0), imm32(-2)
add %10 r64(4), imm8(48)
ret
对象(使用x86-64转储到https://www.onlinedisassembler.com/odaweb/):
48 83 EC 30 48 89 C8 48 8B 10 B9 05 00 00 00 48 89 54 24 28 FF 15 D6 FF FF FF 48 8B 54 24 28 89 42 10 B8 FE FF FF FF 48 83 C4 30 C3
调用的函数就像(发布时失败)一样简单:
int PrintInt(int nr) {
std::cout << nr << std::endl; // error
return nr;
}
错误是: “test.exe中的0x000007FEE3693D39(msvcp140.dll)抛出异常:0xC0000005:访问冲突读取位置0x0000000000000000。”
知道我缺少什么吗?
使用我的评论编辑反汇编
sub rsp, 0x30 // subtract 48 bytes from stack pointer to get 6 slots of space
mov rax, rcx // rcx is a pointer parameter
mov rdx, QWORD PTR [rax] // load pointer from [rax]
mov ecx, 0x5 // imm 5 into ecx for function call
mov QWORD PTR [rsp+0x28], rdx // save rdx for after function call on the stack
call QWORD PTR [..] // function call
mov rdx, QWORD PTR [rsp+0x28] // get rdx back from stack
mov DWORD PTR [rdx+0x10], eax // save result
mov eax, 0xfffffffe // -2 in eax (return value)
add rsp, 0x30 // restore stack ptr (free)
ret
STACK:
.... start
[XXX] used to save rdx
[ ] unused
[ s ]
[ s ]
[ s ]
[ s ] shadow space
.... call
我预留了6个插槽(8个字节),因此我在呼叫路由时得到了16个字节。
感谢您的帮助。