Reputation: 81
I am struggling to understand why this x86 assembly code, compiles fine with gcc 4.2.1 (llvm) on OSX, but gives a segmentation fault when the executable is run:
.globl _main
_main:
push %rbp
mov %rsp, %rbp
mov $1, %rbx
push %rbx
lea L_.str0(%rip), %rdi
mov %rbx, %rsi
call _printf
pop %rbx
pop %rbp
ret
.section __TEXT,__cstring,cstring_literals
L_.str0:
.asciz "%d \000"
I observed that if the pop %rbx
line is moved before call _printf
, then the program works correctly. But why should it fail at all in its original form?
Upvotes: 3
Views: 1130
Reputation: 81
This question is answered in detail by: How to print argv[0] in NASM? and also x86 Assembly on a Mac. It's essentially a gotcha when programming assembly on MacOSX.
To summarize:
printf
).A simple solution is to align the stack pointer (ie, align to a multiple of 16 bytes as per the Sys V requirement) prior to the call, and restore it after the call:
.globl _main
_main:
push %rbp
mov %rsp, %rbp
mov $1, %rbx
lea L_.str0(%rip), %rdi
mov %rbx, %rsi
push %rbx
mov %rsp, %rax ; Save copy of the stack pointer (SP)
and $-16, %rsp ; Align the SP to the nearest multiple of 16.
sub $8, %rsp ; Pad the SP by 8 bytes so that when we ...
push %rax ; push the saved SP (=8 bytes on a 64-bit OS),
; we remain aligned to 16 bytes (8+8 = 16).
call _printf
pop %rax ; retrieve the saved SP
mov %rax, %rsp ; restore SP using saved value.
pop %rbx
pop %rbp
ret
.section __TEXT,__cstring,cstring_literals
L_.str0:
.asciz "%d \000"
Upvotes: 5