2017-09-19 3 views
2

引数付きの簡単なコンソールアセンブリプログラムを作成しようとしています。ここで些細なMacOSアセンブリ64ビットプログラムのスタックアライメントが正しくない

.section __TEXT,__text 

.globl _main 

_main: 

    movl $0, %edi 
    callq _exit 

コンパイルとリンクのスクリプトです:ここでは、コードです

as test.s -o test.o 
ld test.o -e _main -o test -lc 

今プログラムセグメンテーションフォールトで失敗、または引数の個数に応じて、エラーなしで実行し、次のいずれか

$ ./test 
Segmentation fault: 11 
$ ./test 1 
$ ./test 1 2 
$ ./test 1 2 3 
Segmentation fault: 11 
$ ./test 1 2 3 4 
$ ./test 1 2 3 4 5 
Segmentation fault: 11 

など。 LLDBの下

私はより多くの有益なエラーを参照してください。

確か
Process 16318 stopped 
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT) 
    frame #0: 0x00007fffad14b2fa libdyld.dylib`stack_not_16_byte_aligned_error 
libdyld.dylib`stack_not_16_byte_aligned_error: 
-> 0x7fffad14b2fa <+0>: movdqa %xmm0, (%rsp) 
    0x7fffad14b2ff <+5>: int3 

libdyld.dylib`_dyld_func_lookup: 
    0x7fffad14b300 <+0>: pushq %rbp 
    0x7fffad14b301 <+1>: movq %rsp, %rbp 

、私はプログラムの最初の行で実行を停止した場合、私はスタックが16バイトは、いくつかの引数に整列されていないことを確認それは別のもののために整列されています。 System V ABI for AMD64の状態が、その:

The stack pointer holds the address of the byte with lowest address which is part of the stack. It is guaranteed to be 16-byte aligned at process entry.

は、私が何をしないのですか?

+0

OS Xがいくつかの長さの引数に対してABIに違反しているようです。あなたはlibcなしで試したことがありますか?静的にリンクされたバイナリへのプロセスエントリで自分自身(デバッガを使って)のスタックアラインメントをチェックしてみましたか? 'syscall'は直接ですか? (または、終了ステータス= 'rsp&0xf'と' ./test 1 2 3; echo $? 'を設定してスタックの位置合わせを確認してください)。 –

答えて

2

私はOS X上で、カーネルはスタックアライメントがmainになることを保証しないと思います。スタックを手動で配置する必要があります。幸いにも、これはむしろ簡単です。スタックポインタの少なくとも4ビットをゼロにするだけです。場合は、あなたはどこか、元のスタックポインタを格納することを確認し、引数ベクトルやその他のデータをフェッチする必要があります。

_main: 
    mov %rsp,%rax # copy original stack pointer 
    and $-16,%rsp # align stack to 16 bytes 
    push %rax  # save original stack pointer 
    push %rbp  # establish... 
    mov %rsp,%rbp # ...stack frame 
    ...    # business logic here 
    leave   # tear down stack frame 
    pop %rsp   # restore original stack pointer 
    ...    # exit process 

はまた、精神的にあなたのスタック・アライメントを追跡する必要があります。スタック・アライメントが、何もしないmainを持つことが容易になり、あなたがそれで、通常のスタックフレームを使用することができますので、あなたの実際の主な機能を呼び出すことがあります

_main: 
    mov %rsp,%rbx # save original stack pointer 
    and $-16,%rsp # align stack to 16 bytes 
    call _my_main # call actual main function 
    mov %rbx,%rsp # restore original stack pointer 
    ...    # exit process 

をあなたの特定の例のプログラムでは、あなただけのこの最小限を使用することができますコード:

_main: 
    and $-16,%rsp # align stack to 16 bytes 
    xor %edi,%edi # set exit status to zero 
    call _exit  # exit program 
+0

そのように見えます。私は2番目のスニペットに基づいてコードを作成しました。ありがとう! –

+0

System Vアプリケーションバイナリインターフェイス AMD64アーキテクチャプロセッササプリメント (LP64およびILP32プログラミングモデルを使用) ドラフトバージョン0.99.8:*%rspスタックポインタは、 がスタックの一部である最低アドレスのバイトのアドレスを保持します。 *これは通常の関数の '(%rsp + 8)%16 == 0'とは異なります。 – EOF

+0

@EOF:これはまさに関数呼び出しのためのものです。通常の関数の開始時に、 'call'の前にダミーの' push'または 'sub $ 8、%rsp'が必要です。 tailcallに 'jmp exit'を実行します。 'call'命令を実行する前にスタックが16Bで整列していると考えられるので、argsは整列します。また、OPのエラーメッセージに注意してください。 '0x ... a'は0または8ではありません。 –

関連する問題