段故障來源於壞棧對齊(misaligned_stack_error
)。
當你有這樣的問題時,總是嘗試運行你的程序與GDB。它通常會爲您提供更多信息。
但要恢復,當您從C庫調用函數時,堆棧需要對齊16字節的邊界。
這是Mac OS X 32位ABI(注意對於使用SYS V調用約定的64位ABI也是這種情況)的要求。
因此,這裏是你的程序的工作版本,將打印可執行文件的名稱,以及對CLI參數的數量(解釋只是後):
[bits 32]
section .data
hello db "Program name: %s (%i CLI args)", 10, 0
section .text
global start
extern _exit
extern _printf
start:
; Store 'argc' into EAX
pop eax
; Store 'argv' into EBX
pop ebx
; Align stack on a 16 bytes boundary,
; as we'll use C library functions
mov ebp, esp
and esp, 0xFFFFFFF0
; Stack space for local variables
; A little more space than needed, but that will
; ensure the stack is still aligned
sub esp, 16
; Call 'printf': printf(hello, ebx, eax);
mov dword[ esp ], hello
mov dword[ esp + 4 ], ebx
mov dword[ esp + 8 ], eax
call _printf
; Call 'exit': exit(0);
mov dword[ esp ], 0
call _exit
使用編譯:
nasm -f macho -o test.o test.asm
ld -o test test.o -arch i386 -lc -macosx_version_min 10.6
說明:
我們第一家店argc
和argv
在一些REGIST ERS:
pop eax
pop ebx
然後我們對齊在16個字節邊界堆棧:
mov ebp, esp
and esp, 0xFFFFFFF0
你可以做到這一點只有一次,在start
開始,假設你保持一致堆棧,爲本地變量創建空間時。
然後我們爲局部變量創建必要的空間,確保堆棧保持對齊。
在這裏,我們只需要3個堆棧參數的空間,但我們爲4創建空間,以保持堆棧對齊。
sub esp, 16
然後,您可以在該空間中移動值,爲備調用參數:
mov dword[ esp ], hello
mov dword[ esp + 4 ], ebx
mov dword[ esp + 8 ], eax
然後簡單地調用C庫函數,你會好起來的。
請注意,您還可以在this answer (x86 Assembly on a Mac)找到一些有用的信息。
您確定生成的二進制文件只有32位嗎? – Macmade
如果它運行在64位,那麼調用約定不是cdecl,而是系統V. – Macmade
@Macmade,感謝您的信息!如果我想製作64位程序,我會記住這一點。程序*應該*只能是x86,因爲我指定'-arch i386'爲'ld'。當您嘗試在您的機器上構建和運行相同的代碼時會發生什麼? – mcandre