【发布时间】:2016-04-03 20:47:54
【问题描述】:
我希望能够在内联汇编中使用基址指针寄存器 (%rbp)。一个玩具例子是这样的:
void Foo(int &x)
{
asm volatile ("pushq %%rbp;" // 'prologue'
"movq %%rsp, %%rbp;" // 'prologue'
"subq $12, %%rsp;" // make room
"movl $5, -12(%%rbp);" // some asm instruction
"movq %%rbp, %%rsp;" // 'epilogue'
"popq %%rbp;" // 'epilogue'
: : : );
x = 5;
}
int main()
{
int x;
Foo(x);
return 0;
}
我希望,因为我使用的是通常的序言/尾声函数调用方法来推送和弹出旧的%rbp,这样就可以了。但是,当我尝试在内联汇编之后访问x 时,它会出现段错误。
GCC 生成的汇编代码(略微精简)是:
_Foo:
pushq %rbp
movq %rsp, %rbp
movq %rdi, -8(%rbp)
# INLINEASM
pushq %rbp; // prologue
movq %rsp, %rbp; // prologue
subq $12, %rsp; // make room
movl $5, -12(%rbp); // some asm instruction
movq %rbp, %rsp; // epilogue
popq %rbp; // epilogue
# /INLINEASM
movq -8(%rbp), %rax
movl $5, (%rax) // x=5;
popq %rbp
ret
main:
pushq %rbp
movq %rsp, %rbp
subq $16, %rsp
leaq -4(%rbp), %rax
movq %rax, %rdi
call _Foo
movl $0, %eax
leave
ret
谁能告诉我为什么这个段错误?似乎我以某种方式破坏了%rbp,但我不知道如何。提前致谢。
我在 64 位 Ubuntu 14.04 上运行 GCC 4.8.4。
【问题讨论】:
-
不要添加无关语言的标签。
-
对于汇编代码:使用汇编参数指定C端变量;不要依赖汇编代码中的特定寄存器布局。并且总是指定clobbers。
-
movq %rdi, -8(%rbp)将 RDI 置于红色区域。然后您执行pushq %rbp;将 RSP 减 8 并将值放在 RBP 中。不幸的是,由于 RSP=RBP 您只是覆盖了 GCC 存储在那里的值(假设是 RDI)。在您的内联汇编程序完成后,它尝试了movq -8(%rbp), %rax。好吧,我们刚刚了解到您在内存位置-8(%rbp)处删除了数据,因此它现在包含一个虚假值,然后我们尝试使用movl $5, (%rax)取消引用它。该指令可能会出现段错误,因为 RAX 不再具有有效指针。 -
如果你想在内联汇编器中使用 C/C++ 变量,你真的需要开始使用输入(和输出,如果需要)约束来允许数据传入(和/或传出)。跨度>
标签: c++ gcc x86 inline-assembly red-zone