3

レジスタに保存してから出力したいargv[0]のですが、アセンブリ プログラムを実行するとセグメンテーション違反が発生します。

痕跡:

$ nasm -f macho -o scriptname.o --prefix _ scriptname.asm
$ ld -o scriptname scriptname.o -arch i386 -lc -macosx_version_min 10.6 -e _start -no_pie
$ ./scriptname
Segmentation fault: 11

スクリプト名.asm:

[bits 32]

section .data

program: db "Program: %s", 0

section .text

global start
extern printf
extern exit

start:

; skip argc
add esp, 4

; ebx := argv[0]
pop ebx

push ebx
push program
call printf
add esp, 8

push 0
call exit

仕様:

  • ld 64-134.9
  • nasm 0.98.40
  • Xcode 4.5
  • Mac OS X 10.8.2
  • MacBook Pro 2009
4

1 に答える 1

5

セグメンテーション違反は、不適切なスタック アライメントが原因です( 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 アセンブリ) にも役立つ情報がいくつかあることに注意してください。

于 2012-10-01T19:21:39.593 に答える