【问题标题】:How to write assembly language hello world program for 64 bit Mac OS X using printf?如何使用 printf 为 64 位 Mac OS X 编写汇编语言 hello world 程序?
【发布时间】:2023-03-16 13:44:01
【问题描述】:

我正在尝试学习为 64 位 Mac OS 编写汇编语言。我对 32 位 Mac OS 以及 32 位和 64 位 Linux 都没有问题。

但是,Mac OS 64 位是不同的,我无法弄清楚。因此,我在这里寻求帮助。

使用系统调用打印没有问题。但是,我想学习如何使用 Mac OS 的 64 位汇编语言调用 C 函数。

请看下面的代码

.data
_hello:
    .asciz "Hello, world\n"


.text
.globl _main
_main:
    movq $0, %rax
    movq _hello(%rip), %rdi
    call _printf

我用 $ gcc -arch x86_64 hello.s

组装和链接。

它生成二进制代码。但是,我在运行它时遇到了分段错误。

我尝试在调用 _printf 之前添加“subq $8, %rsp”,结果还是和之前一样。

我做错了什么?

顺便问一下,有没有办法在 Mac 上调试这段代码?我尝试添加 -ggdb 或 -gstab 或 -gDWARF,并且 $gdb ./a.out,看不到代码和设置断点。

【问题讨论】:

标签: macos assembly 64-bit printf 32bit-64bit


【解决方案1】:

您没有确切说明您看到的问题是什么,但我猜您在调用printf 时崩溃了。这是因为 OS X(32 位和 64 位)要求堆栈指针在任何外部函数调用处都具有 16 字节对齐。

调用_main 时堆栈指针是16 字节对齐的;该调用将一个 8 字节的返回地址推入堆栈,因此在调用 _printf 时堆栈不是 16 字节对齐的。在调用之前从%rsp 中减去八,以便正确对齐。


所以我继续为你调试了这个(不涉及魔法,只需使用 gdb、break maindisplay/5i $pcstepi 等)。您遇到的另一个问题是:

movq _hello(%rip), %rdi

这会将字符串的前 8 个字节加载到 %rdi 中,这根本不是您想要的(特别是,字符串的前 8 个字节极不可能构成指向格式字符串的有效指针,这会导致printf 崩溃)。相反,您想加载字符串的 地址。您的程序的调试版本是:

.cstring
_hello: .asciz "Hello, world\n"

.text
.globl _main
_main:
    sub  $8, %rsp           // align rsp to 16B boundary
    mov  $0, %rax
    lea  _hello(%rip), %rdi // load address of format string
    call _printf            // call printf
    add  $8, %rsp           // restore rsp
    ret

【讨论】:

  • 谢谢,斯蒂芬。我知道 16 字节堆栈对齐问题。我添加了 subq $8, %rsp 并且仍然出现分段错误...我怀疑 movq _hello(%rip), %rdi,我不确定这是正确的。在 Linux 上我可以只使用 movq _hello, %rdi,但是 mac 会抱怨不支持绝对地址。
  • 再次感谢斯蒂芬!有用!多么神奇!我实际上尝试使用 leaq。但是,我没有意识到即使不向堆栈压入任何参数,堆栈仍然必须对齐 16 个字节。多么令人困惑的情况!
  • 这里的%rdi是什么?
  • @KorayTugay:你在问什么并不明显; %rdi 是一个寄存器名称,特别是包含在 OS X x86_64 调用约定下的函数调用的第一个整数/指针参数(在本例中为指针)的寄存器名称。
猜你喜欢
  • 2011-02-08
  • 1970-01-01
  • 2013-12-03
  • 1970-01-01
  • 2010-11-04
  • 2016-06-28
  • 2011-05-16
相关资源
最近更新 更多