アセンブリ言語の教科書 第3章 Hello, GAS world!!

サンプルに少し改良を加えました。

.text
.global main

main:   push %ebp
        mov  %esp,%ebp
        push $hello
        call printf
        
        mov  $0, %eax
        leave
        ret

.data
hello: .string "Hello, GAS World!!"

一見何の変哲もないHello,Worldですが、かなり罠が隠れています。1行づつ罠を解いていきます。

復習ついでに、ベースポインタ入門をしてみる。

ボクノス的ベースポインタ入門

---------------------------------------------
|  |  |  |  |  |  |  |呼び出し元のアドレス|
---------------------------------------------
                     ^%esp             ^%ebp

最初はこの状態。スタックは右から左へ積んでいきます。スタックには、呼び出し元のアドレスが入ってます。アドレスを間違えるととんでもない所に飛んでいくので注意しましょう。

push %ebpで、呼び出し元のベースポインタを積む。

----------------------------------------------------------------
|  |  |  |  |  |  |呼び出し元のベースポインタ|呼び出し元のアドレス|
-----------------------------------------------------------------
                  ^%esp                                    ^%ebp←コレを積む

ベースポインタ%ebpは、スタックの底を表す。関数呼び出し直後に定義し、元の関数へ確実に戻れる足がかりを作る。その他に、変数定義や、バックトレース、フレーム処理等にも使われる。

現在の%espを%ebpに代入する。

----------------------------------------------------------------
|  |  |  |  |  |  |呼び出し元のベースポインタ|呼び出し元のアドレス|
-----------------------------------------------------------------
                  ^%esp^%ebp

今は、%esp == %ebpな状態。後はpushで左へ積んでいけばOK。

実はこのサンプルでは、Hello,Worldよりespとebpの関係の方が重要なのだ!!(と僕は思う)

pushしてpopしてない。

そう、コレがベースポインタの凄い所。pushしたら、popするのが流儀。しかし、popしなくても、ベースポインタでスタックの底を定義してるので、leaveで確実にスタックの底へたどり着ける!!

leave

leaveすると、最初の状態まで戻る。enterはあんまりよくわかってない。

まとめ

  • 試しにpopしまくってみて、ちゃんと戻れる事を確認して欲しい。
  • %epb->%epb->%epb->%epbと辿ることで、バックトレースを取ることが出来る。
  • 4(%ebp)に呼出し元アドレスが入っているので、色々活用が効く。
  • 前の関数の変数定義を覗き見することも出来る。
  • スタック重要。

復習終了。

OS自作入門で散々ハマったからな・・・。

参考