在clang-cl中确保自定义ASM函数的x64合规性
问题:x64静态库内联汇编缺失Shadow Space的解决方法
我为自定义编译的原生x64 JIT代码实现了一些固有函数,多数由自研编译器生成,部分需被C++代码直接调用,因此希望将这些函数编译进静态库以支持静态链接甚至内联。
由于这些函数需要执行常规C++无法表达的操作(如通过函数输入设置非易失性寄存器),必须使用内联汇编。但函数本身需表现得像标准x64函数:具备序言/尾声,且拥有支持堆栈追踪和异常处理的必要unwind信息。因此我放弃原生编译器MSVC,转而在Visual Studio中用clang-cl编译静态库,当前实现代码如下:
void interruptEntry(void* pState, const char* pAddress) { __asm { // load state into RBX mov rbx,rcx // load callstack-top into RDI mov rax,[rbx] mov rdi,[rax] // call address call rdx }; }
这段代码能生成正确的序言、尾声及所需unwind信息,但关键缺失x64要求的32字节shadow space(pAddress调用依赖该空间),生成的汇编代码如下:
Acclimate Engine.dll!interruptEntry(void *, const char *): push rdi push rbx mov rbx,rcx mov rax,qword ptr [rbx] mov rdi,qword ptr [rax] call rdx pop rbx pop rdi ret
注意:代码由clang-cl生成,但DLL通过MSVC链接,静态库以O2优化编译。
我已尝试的方案:
- 手动修改RSP(
sub RSP,32):编译器会将其视为动态栈分配,建立帧指针,开销过大; - 在汇编中直接引用pState(
mov rbx,pState):虽会添加shadow space,但pState会被复制到栈中再加载,违背初衷; - 在汇编块后直接调用
pAddress函数指针:代码生成无变化; - 结合
asm()/扩展asm与__attribute__((naked)):需手动编写序言/尾声,但clang-cl不识别.allocstack、.pushreg等unwind数据指令,报错“unknown directive”。
请问shadow space缺失的原因是什么?有无方法在不添加帧指针这类额外开销的前提下生成shadow space,同时保留unwind信息?也欢迎其他建议,比如是否存在可直接设置指定寄存器的固有函数(编译后仅对应一条mov指令),这样我就无需使用汇编(操纵具有全局影响的特定寄存器是无法用纯C++实现的核心原因)。
内容的提问来源于stack exchange,提问作者Juliean
相关产品推荐
相关产品推荐

