Вызов C-функции _printf из NASM вызывает сбой сегментации - PullRequest
0 голосов
/ 11 июля 2019

Я пытался изучить 64-битную сборку на Mac-OS и Windows, используя NASM.

Мой код

extern _printf

section .data
    msg db "Hello World!", 10, 0

section .text
    global _main

_main:
    mov rax, 0
    mov rdi, msg
    call _printf

    mov rax, 0x2000001
    mov rdi, 0
    syscall

и я компилирую с

nasm -f macho64 -o main.o main.asm 
gcc -o main main.o

При попытке позвонить _printf я получил ошибку

Ошибка сегментации: 11

Когда я удаляю вызов на _printf, мой код работает нормально. Почему вызов _printf вызывает ошибку сегментации?

Я нашел здесь соглашение о вызовах ABI , но не смог успешно вызвать C-функцию.

Я ожидаю, что будет напечатано Hello World!, но вместо этого я получу 'Ошибка сегментации: 11'.

1 Ответ

3 голосов
/ 11 июля 2019

~~ Вам необходимо установить кадр стека перед вызовом _printf

TL; DR: Системный V AMD64 ABI требует, чтобы указатель стека был выровнен по 16 байтов. Ко времени вызова _printf указатель стека смещается на 8 байт.

Отладка двоичного файла с помощью LLDB дает:

frame # 0: 0x00007fff527d430a libdyld.dylib`stack_not_16_byte_aligned_error

MacOS использует ABI System V AMD64 и поэтому использует 16-байтовое выравнивание для указателя стека ( см. Этот вопрос ), короче говоря, это означает, что указатель стека (rsp) должен всегда делится на 16 при вызове функции.

Ко времени вызова _printf указатель стека (rsp) смещается на 8 байтов. Как это случилось?

Я нашел ответ на этой странице , вызов функции _main помещает адрес возврата (8 байт) в стек и, следовательно, смещает его.

Моя первоначальная идея - установка фрейма стека - поместила еще один адрес в стек, и поэтому rsp снова делился на 16.

Однако более простое решение будет просто sub rsp, 8, как предлагает Маргарет Блум

Измените свой код на:

extern _printf

section .data
    msg: db "Hello World!", 10, 0

section .text
    global _main

_main:
    ;; Fix the stack alignment
    sub rsp, 8
    mov rax, 0
    mov rdi, msg
    call _printf

    mov rax, 0x2000001
    mov rdi, 0
    syscall

Протестировано на macOS 10.13.6

...