セグメンテーション違反は、不適切なスタック アライメントが原因です( 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
をいくつかのレジスタに保存します。
pop eax
pop ebx
次に、スタックを 16 バイト境界に合わせます。
mov ebp, esp
and esp, 0xFFFFFFF0
ローカル変数用のスペースを作成するときに、スタックを整列したままにしておくstart
と仮定すると、これは の最初に 1 回だけ実行できます。
次に、ローカル変数に必要なスペースを作成し、スタックが整列されていることを確認します。
ここでは、3 つのスタック引数用のスペースしか必要ありませんが、スタックの整列を維持するために 4 つのスペースを作成します。
sub esp, 16
次に、そのスペースで値を移動して、呼び出しの引数を準備できます。
mov dword[ esp ], hello
mov dword[ esp + 4 ], ebx
mov dword[ esp + 8 ], eax
次に、C ライブラリ関数を呼び出すだけで問題ありません。
この回答 (Mac 上の x86 アセンブリ) にも役立つ情報がいくつかあることに注意してください。