以下汇编代码在 OSX 10.9.4 上运行 as
时出错,但在 Linux (Debian 7.6) 上运行成功。特别是,movq 指令似乎不喜欢标签参数。
$ cat test.S
.globl _main
_main:
movq $_main, %rax
ret
这里是错误:
$ as -o test.o test.S
test.S:3:32-bit absolute addressing is not supported for x86-64
test.S:3:cannot do signed 4 byte relocation
将第 3 行中的 $_main
更改为类似 $10
的字面量效果很好。
必须以非常小的方式修改代码才能使其在 Linux 上运行 - 只需从标签中删除下划线即可。
$ cat test.S
.globl main
main:
movq $main, %rax
ret
独立验证代码是否在 Linux 上运行非常容易:
$ as -o test.o test.S
$ gcc -o test.out test.o
$ ./test.out
请忽略该代码并没有真正做任何事情,我故意尽可能地减少它以证明错误。
我已经仔细研究了 LEA(加载有效地址)的使用,但在我进行更改之前,我想了解其中的区别 - 为什么它适用于 Linux 而不是 OSX?
最佳答案
关于 movq
指令不能引用绝对地址的说法是正确的。这部分是由于 OS X ABI Mach-O对符号使用可重定位寻址的格式。
被编译为位置无关可执行文件 (PIE
) 的程序通常不能像 movq $_main, %rax
那样引用绝对虚拟地址.相反,Global Offset Tables被调用,它允许位置相关代码 (PC-rel
) 和位置无关代码 (PIC
) 在它们当前的绝对地址位置提取全局符号。如下所示,GOTPCREL(%rip)
创建了 lea rdi, _msg
的解释:
引用其全局偏移表的 PC-rel 代码:
.globl _main
_main:
movq _main@GOTPCREL(%rip), %rax
sub $8, %rsp
mov $0, %rax
movq _msg@GOTPCREL(%rip), %rdi
call _printf
add $8, %rsp
ret
.cstring
_msg:
.ascii "Hello, world\n"
Mac OS X Mach-O 汇编程序:
$ as -o test.o test.asm
Apple 版本的 GCC:
$ gcc -o test.out test.o
输出:
$ ./test.out
Hello, world
关于linux - 为什么这个 movq 指令适用于 linux 而不是 osx?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25799551/