linux - 为什么这个 movq 指令适用于 linux 而不是 osx?

标签 linux macos x86-64

以下汇编代码在 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/

相关文章:

linux - MV : missing file operand while using mv in shell script but not in terminal

multithreading - 如何在 OS X 内核中实现带有超时的递归互斥锁?

objective-c - 重新启动已启动的应用程序

c++ - 为什么在mac中禁止使用fork without exec?

c - 在不调试的情况下查找导致 Illegal Instruction 错误的汇编指令

c - 我从汇编代码到 C 代码的转换是否正确?

linux - 如何在 var 的末尾 append 双引号 (")

linux - bash , tar "cannot stat no such file or directory"

Linux 内核——刷新 VFS Dentry 缓存