我一直在玩C中的asm
宏来直接调用OS X Mavericks上的一些汇编指令来获取堆栈指针地址(来自%rsp)并且我发现了真的尝试将汇编程序代码的返回值分配到%rax寄存器(按惯例应该保存函数返回值的那个)时,奇怪的行为(至少对我来说)。 C代码非常简单:
#include <stdio.h>
unsigned long long get_sp(void) {
asm ("mov %rsp, %rax");
return 0;
}
int main(void) {
printf("0x%llx\n", get_sp());
}
如果我编译并运行代码,则会打印%rax寄存器中的值(实际堆栈指针),这很奇怪,因为我希望%#xx寄存器被&#34覆盖;返回0;&# 34;
但是,如果我删除return 0;
一个字符串&#34; 0x0&#34;得到打印也很奇怪,因为我希望读取和打印%rax寄存器的返回值。
我也尝试在Ubuntu Linux上运行此代码(使用%esp和%eax寄存器的唯一区别),它实际上可以正常工作(使用gcc编译器)。
这可能是llvm-gcc编译器(Apple LLVM版本5.1)中的错误吗?
//修改 这是没有&#34;返回0;&#34;
的版本otool -tV sp.out
sp.out:
(__TEXT,__text) section
_get_sp:
0000000100000f30 pushq %rbp
0000000100000f31 movq %rsp, %rbp
0000000100000f34 movq %rsp, %rax
0000000100000f37 movq -0x8(%rbp), %rax
0000000100000f3b popq %rbp
0000000100000f3c ret
0000000100000f3d nopl (%rax)
_main:
0000000100000f40 pushq %rbp
0000000100000f41 movq %rsp, %rbp
0000000100000f44 subq $0x10, %rsp
0000000100000f48 callq _get_sp
0000000100000f4d leaq 0x3a(%rip), %rdi ## literal pool for: "0x%llx
"
0000000100000f54 movq %rax, %rsi
0000000100000f57 movb $0x0, %al
0000000100000f59 callq 0x100000f6e ## symbol stub for: _printf
0000000100000f5e movl $0x0, %ecx
0000000100000f63 movl %eax, -0x4(%rbp)
0000000100000f66 movl %ecx, %eax
0000000100000f68 addq $0x10, %rsp
0000000100000f6c popq %rbp
0000000100000f6d ret
答案 0 :(得分:2)
这不是错误。这是不正确使用内联汇编的结果。在包含return语句的情况下,编译器不检查asm语句。如果在asm块之前%rax
已经设置为零,则指令将覆盖该值。 asm块之前,编译器可以自由地执行此操作,因为您还没有通知任何寄存器输出,clobbers等。
如果不包含return语句,则不能依赖返回值。这就是为什么clang(这就是llvm-gcc与Xcode 5.1的关系 - 它不是gcc前端)发出警告。 gcc-4.8.2似乎适用于OS X - 但由于代码在两种情况下都不正确,所以它只是“运气”。通过优化:-O2
,它不再有效。默认情况下,gcc不会发出警告,这是至少使用-Wall
的一个很好的理由。
{
unsigned long long ret;
__asm__ ("movq %rsp, %0" : "=r" (ret));
return ret;
}
始终有效。 volatile
不是必需的,因为编译器正在使用输出,因此它不能丢弃asm语句。即使将第一行更改为unsigned long long ret = 0;
- 编译器显然也无法重新排序。
答案 1 :(得分:0)
这适用于我在小牛队[编辑:在Ubuntu Saucy x86_64上没有任何改变]:
#include <stdio.h>
unsigned long long get_sp(void) {
long _sp = 0x0L;
__asm__ __volatile__(
"mov %%rsp, %[value] \n\t"
: [value] "=r" (_sp)
:
:);
return _sp;
}
int main(void) {
printf("0x%llx\n", get_sp());
}