如何使用printf为64位Mac OS X编写汇编语言hello world程序?

时间:2023-01-01 02:42:48

I am trying to learn writing assembly language for 64 bit Mac OS. I have no problem with 32 bit Mac OS and both 32 bit and 64 bit Linux.

我正在努力学习为64位Mac OS编写汇编语言。我对32位Mac OS以及32位和64位Linux没有任何问题。

However, Mac OS 64 bit is different and I couldn't figure out. Therefore I am here to ask for help.

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

I have not problem using system call to print. However, I would like to learn how to call C functions using 64 bit assembly language of Mac OS.

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

Please look at the following code

请查看以下代码

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


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

I use $ gcc -arch x86_64 hello.s

我使用$ gcc -arch x86_64 hello.s

to assemble and link.

组装和链接。

It generates binary code. However, I got a segmentation fault when running it.

它生成二进制代码。但是,运行它时出现了分段错误。

I tried adding "subq $8, %rsp" before calling _printf, still the same result as before.

我在调用_printf之前尝试添加“subq $ 8,%rsp”,仍然和以前一样。

What did I do wrong?

我做错了什么?

By the way, is that any way to debug this code on Mac? I tried adding -ggdb or -gstab or -gDWARF, and $gdb ./a.out, and can't see the code and set break points.

顺便说一下,这是在Mac上调试此代码的方法吗?我尝试添加-ggdb或-gstab或-gDWARF和$ gdb ./a.out,但无法查看代码并设置断点。

1 个解决方案

#1


8  

You didn't say exactly what the problem you're seeing is, but I'm guessing that you're crashing at the point of the call to printf. This is because OS X (both 32- and 64-bit) requires that the stack pointer have 16-byte alignment at the point of any external function call.

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

The stack pointer was 16-byte aligned when _main was called; that call pushed an eight-byte return address onto the stack, so the stack is not 16-byte aligned at the point of the call to _printf. Subtract eight from %rsp before making the call in order to properly align it.

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


So I went ahead and debugged this for you (no magic involved, just use gdb, break main, display/5i $pc, stepi, etc). The other problem you're having is here:

所以我继续为你调试这个(没有魔法,只需使用gdb,break main,display / 5i $ pc,stepi等)。你遇到的另一个问题是:

movq _hello(%rip), %rdi

This loads the first eight bytes of your string into %rdi, which isn't what you want at all (in particular, the first eight bytes of your string are exceedingly unlikely to constitute a valid pointer to a format string, which results in a crash in printf). Instead, you want to load the address of the string. A debugged version of your program is:

这会将字符串的前八个字节加载到%rdi中,这根本不是您想要的(特别是,字符串的前八个字节极不可能构成指向格式字符串的有效指针,这会导致在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

#1


8  

You didn't say exactly what the problem you're seeing is, but I'm guessing that you're crashing at the point of the call to printf. This is because OS X (both 32- and 64-bit) requires that the stack pointer have 16-byte alignment at the point of any external function call.

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

The stack pointer was 16-byte aligned when _main was called; that call pushed an eight-byte return address onto the stack, so the stack is not 16-byte aligned at the point of the call to _printf. Subtract eight from %rsp before making the call in order to properly align it.

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


So I went ahead and debugged this for you (no magic involved, just use gdb, break main, display/5i $pc, stepi, etc). The other problem you're having is here:

所以我继续为你调试这个(没有魔法,只需使用gdb,break main,display / 5i $ pc,stepi等)。你遇到的另一个问题是:

movq _hello(%rip), %rdi

This loads the first eight bytes of your string into %rdi, which isn't what you want at all (in particular, the first eight bytes of your string are exceedingly unlikely to constitute a valid pointer to a format string, which results in a crash in printf). Instead, you want to load the address of the string. A debugged version of your program is:

这会将字符串的前八个字节加载到%rdi中,这根本不是您想要的(特别是,字符串的前八个字节极不可能构成指向格式字符串的有效指针,这会导致在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