如果我有以下代码,那么第二个寄存器读取将始终为0。
因此示例输出将是:
帧指针1560061208
堆栈指针0
位置1560061159处的字符
如果我将调用交换到rbp和rsp,那么第二个调用总是输出0。
#include <stdio.h>
int main() {
void *bp asm("rbp");
printf("Frame pointer %u\n", bp);
void *sp asm("rsp");
printf("Stack pointer %u\n", sp);
char c = 'A';
printf("Character at location %u\n", &c);
return 0;
}
答案 0 :(得分:3)
The only supported use of type variable asm("regname");
is to control inputs to Extended-asm
statements。因此,您的代码在GNU C中具有未定义的行为,并且您不应期望从中获得有意义的结果。
您可以使用内联asm将%rsp
复制到另一个寄存器,并且可能有一些GNU C内置函数来获取堆栈或帧指针;我忘了。如果您要对堆栈指针做任何事情,您应该只是在asm中编写整个函数。
register
关键字。始终检查编译器警告,特别是在执行&#34;奇怪的&#34;东西,其中包含带有asm
关键字的任何。或者任何时候你没有得到预期的输出。
gcc7.2 -O3 -Wall说:
5 : <source>:5:11: warning: ignoring asm-specifier for non-static local variable 'bp'
void *bp asm("rbp");
^~
... format-string warnings you should fix...
6 : <source>:6:5: warning: 'bp' is used uninitialized in this function [-Wuninitialized]
printf("Frame pointer %u\n", bp);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
如果你写register void *bp asm("rbp");
它似乎有效,将寄存器值按照你期望的方式传递给printf。
gcc7.2 -O3 -Wall on the Godbolt compiler explorer,修复了错误并使用register
关键字注册asm locals。请记住,这不是支持的,但确实碰巧在gcc7.2 for x86-64中做了你想做的事。
main:
push rbp # save the old rbp (but it *isn't* making a "stack frame" with mov rbp, rsp)
mov rsi, rbp # copy rbp (caller's value) as 2nd arg to printf
mov edi, OFFSET FLAT:.LC0 # format string
xor eax, eax
sub rsp, 16 # IDK why gcc allocates more stack space
call printf
mov rsi, rsp # pass current rsp as 2nd arg to printf
mov edi, OFFSET FLAT:.LC1
xor eax, eax
call printf
lea rsi, [rsp+15] # &c
mov edi, OFFSET FLAT:.LC2
xor eax, eax
mov BYTE PTR [rsp+15], 65
call printf
add rsp, 16
xor eax, eax
pop rbp # restore caller's RBP even though we didn't modify it
ret
可能使用rbp
作为寄存器asm变量使得gcc就好像它是&#34;使用&#34;,因此保存&amp;恢复。
如果您想要堆叠帧,请使用-fno-omit-frame-pointer
。 (这是-O0的默认值,but nobody wants to read gcc -O0
output。)