6

夏休みにx86アセンブリを学ぶのは楽しいだろうと思いました。それで、私は非常に単純なhello worldプログラムから始めました、無料の例を借りるgcc -Sことは私に与えることができました。私はこれで終わった:

HELLO:
    .ascii "Hello, world!\12\0"
    .text

.globl _main
_main:
    pushl   %ebp        # 1. puts the base stack address on the stack
    movl    %esp, %ebp  # 2. puts the base stack address in the stack address register
    subl    $20, %esp   # 3. ???
    pushl   $HELLO      # 4. push HELLO's address on the stack
    call    _puts       # 5. call puts
    xorl    %eax, %eax  # 6. zero %eax, probably not necessary since we didn't do anything with it
    leave               # 7. clean up
    ret                 # 8. return
                        # PROFIT!

コンパイルして動作します!そして、私はそれのほとんどを理解していると思います。

ただし、手順3で魔法が発生します。この行を削除するputsと、スタックエラーの呼び出しとxorスタックエラーの間にプログラムが停止します。そして、私$20が別の値に変更すると、それもクラッシュします。veryそれで、この値が重要であるという結論に達しました。

問題は、それが何をするのか、なぜそれが必要なのかわからないということです。

誰かが私を説明できますか?(私はMac OSを使用していますが、それが問題になることはありません。)

4

3 に答える 3

3

コメントの一般的な形式は、「ローカル変数にスペースを割り当てる」である必要があります。なぜそれを恣意的に変更するとクラッシュするのかわかりません。あなたがそれを減らす場合にのみ、私はそれがクラッシュするのを見ることができます。そして、6の適切なコメントは、「この関数から0を返す準備をする」です。

于 2010-06-06T02:48:56.147 に答える
3

x86 OSX では、関数呼び出し用にスタックを 16 バイトに揃える必要があります。ABI のドキュメントはこちらを参照してください。というわけで、解説は

プッシュ スタック ポインタ (#1) -4
奇妙な増分 (#3) -20
push 引数 (#4) -4
コールは戻りアドレスをプッシュします (#5) -4
合計 -32

確認するには、行番号 3 を $20 から $4 に変更します。これも機能します。

また、Ignacio Vazquez-Abrams は、#6 はオプションではないと指摘しています。レジスタには以前の計算の残りが含まれているため、明示的にゼロにする必要があります。

私も最近、組み立てを学びました(まだ学んでいます)。ショックを避けるために、64 ビットの呼び出し規則は大きく異なります (パラメーターはレジスターで渡されます)。これは、64ビットのアセンブリに非常に役立ちます。

于 2010-06-06T04:05:26.000 に答える
1

-fomit-frame-pointer を指定してコンパイルすると、その%ebpポインタのボイラープレートの一部が消えることに注意してください。ベース ポインターはデバッグに役立ちますが、x86 では実際には必要ありません。

また、すべての GCC/binutils でサポートされている Intel 構文を使用することを強くお勧めします。以前は、AT&T と Intel の構文の違いは単なる好みの問題だと思っていましたが、ある日、AT&T のニーモニックが Intel のニーモニックとまったく異なるこの例に出くわしました。また、x86 の公式ドキュメントはすべて Intel 構文を使用しているため、それがより良い方法のように思えます。

楽しむ!

于 2010-06-06T04:53:40.077 に答える