Как написать ассемблер hello world program для 64-битной Mac OS X с помощью printf?

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

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

У меня нет проблем с использованием системного вызова для печати. Тем не менее, я хотел бы узнать, как вызывать функции 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

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

Указатель стека был выровнен по 16 байт при вызове _main; этот вызов переместил 8-байтовый обратный адрес в стек, поэтому стек не выравнивается по 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