这段代码的问题非常简单。在使用 AT&T 语法的 GNU 汇编器中 -
用作立即操作数的文字常量需要以前缀$
(美元符号)否则常量将被视为内存操作数。
这些行都存在这个问题:
subq obj_size, %rsp
movq 1, %rax
[snip]
addq obj_size, %rsp
在这些情况下,因为您想使用常量obj_size
and 1
作为值(立即操作数)而不是内存引用。上面的说明应该是:
subq $obj_size, %rsp
movq $1, %rax
[snip]
addq $obj_size, %rsp
subq obj_size, %rsp
尝试从内存地址 0x8 处的值中减去 64 位值RSP. movq 1, %rax
尝试将内存地址 0x1 处的 64 位值移至RAX。您的程序出现故障,因为无法读取 OS/X 上的这些内存位置。
一篇关于 AT&T 语法和 Intel 语法之间差异的好文章可以在IBM 的网站。他们特别列出了以下差异:
在 AT&T 语法中,立即数操作数前面带有 $;在 Intel 语法中,立即操作数不是。例如:英特尔:push 4
,美国电话电报公司:pushl $4
为了缩小此类问题的范围,使用调试器通常是有益的。在 OS/X 上,如果您不使用 Xcode,则可以使用调试器LLDB从命令行。 A使用教程LLDB可能有用。在这种情况下你可以运行LLDB as lldb ./nameofprogram
然后使用run
命令允许它继续,直到失败。然后调试器会向您显示崩溃发生在哪条汇编指令上。
如果您想了解 64 位 OS/X 代码使用的调用约定苹果是这样定义的:
OS X x86-64 函数调用约定与 System V 应用程序二进制接口 AMD64 架构处理器补充中描述的函数调用约定相同。
您可以找到 System V 应用程序二进制接口 AMD64 架构处理器补充here。调用者和被调用者保存的寄存器列表可以在图 3.4:寄存器使用