Как написать программу на языке ассемблера hello world для 64-битной Mac OS X с использованием printf? - PullRequest
14 голосов
/ 01 января 2012

Я пытаюсь научиться писать на ассемблере для 64-битной Mac OS.У меня нет проблем с 32-битной Mac OS и как с 32-битной, так и с 64-битной Linux.

Однако, 64-битная Mac OS отличается, и я не могу понять.Поэтому я здесь, чтобы попросить о помощи.

У меня нет проблем с использованием системного вызова для печати.Однако я хотел бы узнать, как вызывать функции C, используя 64-битный язык ассемблера Mac OS.

Пожалуйста, посмотрите на следующий код

.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

для сборки и компоновки.

Он генерируетбинарный код.Однако при его запуске возникла ошибка сегментации.

Я пытался добавить «subq $ 8,% rsp» перед вызовом _printf, но результат тот же, что и раньше.

Что я сделал не так?

Кстати, есть ли способ отладки этого кода на Mac?Я попытался добавить -ggdb или -gstab или -gDWARF и $ gdb ./a.out, и не могу увидеть код и установить точки останова.

1 Ответ

8 голосов
/ 01 января 2012

Вы не сказали точно, в чем проблема, с которой вы сталкиваетесь, но я предполагаю, что вы терпите крах в точке вызова на printf. Это связано с тем, что OS X (32- и 64-разрядная) требует, чтобы указатель стека имел 16-байтовое выравнивание в точке вызова любой внешней функции.

Указатель стека был выровнен на 16 байтов при вызове _main; этот вызов поместил восьмибайтовый адрес возврата в стек, поэтому стек не выровнен по 16 байтов в точке вызова на _printf. Вычтите восемь из %rsp перед выполнением вызова, чтобы правильно выровнять его.


Так что я пошел дальше и отладил это для вас (без магии, просто используйте gdb, break main, display/5i $pc, stepi и т. Д.). Другая проблема у вас здесь:

movq _hello(%rip), %rdi

Это загружает первые восемь байтов вашей строки в %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
...