0

I've been trying to learn 64-bit assembly on both Mac-OS and Windows using NASM.

My code is

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

and I compile it with

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

While trying to call _printf, I got the error

Segmentation fault: 11

When I remove the call to _printf, my code runs fine. Why does the call to _printf cause a segmentation fault?

I have found the ABI Calling Convention here, but had no luck successfully calling a C-function.

I would expect Hello World! to be printedd, however I get 'Segmentation Fault: 11' instead.

kalehmann
  • 4,821
  • 6
  • 26
  • 36
  • Are you sure that `mov rdi, msg` is being encoded as `mov r64, imm64` and not `mov r/m64, imm32`? Try using `mov rdi, qword msg` instead. – Michael Jul 11 '19 at 14:20
  • You might try to call that function in C and look at the created assembler output. – Gerhardh Jul 11 '19 at 14:20
  • @Michael I changed the line, and the output has not changed. – TrashWithNoLid Jul 11 '19 at 14:22
  • @Gerhardh I have tried doing that before, however I have a hard time understanding the vast majority of it besides the very basic, especially because of the different syntax. – TrashWithNoLid Jul 11 '19 at 14:26

1 Answers1

3

~~You need to setup a stack frame before calling _printf

TL;DR: The System V AMD64 ABI requires the stack-pointer to be 16-byte-aligned. By the time of calling _printf, the stack-pointer is misaligned by 8 bytes.

Debugging the binary with LLDB gives:

frame #0: 0x00007fff527d430a libdyld.dylib`stack_not_16_byte_aligned_error

MacOS uses the System V AMD64 ABI and therefore relies on 16-byte alignment for the stack-pointer (see this question), in short this means the stack-pointer (rsp) should always be divisible by 16 when calling a function.

By the time of calling _printf, the stack-pointer (rsp) is misaligned by 8 bytes. How did this come?

I found the answer on this page, calling the _main function pushes the return address (8 bytes) on the stack and therefore misaligns it.

My initial idea - the setup of the stack frame - pushed another address on the stack and therefore rsp was divisible by 16 again.

However an easier solution would be just sub rsp, 8 as suggested by Margaret Bloom

Change your code to:

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

Tested on macOS 10.13.6

kalehmann
  • 4,821
  • 6
  • 26
  • 36