[復習]main にたどり着く前を追ってみた
先日、main
に至るまで追ってみたが幾つか疑問を残していた。
main
からのバックトレースで外側が見えないのは何故か?__libc_start_main
のdisassembleとobjdumpの結果が異なる
詳細にmainまでの挙動を解説しているページがあった。 読んだり他を調べた中で印象に残った部分を記録する。資料も最後にまとめておく。
ただし依然main
からの復帰後にバックトレースが表示できる理由がわからないまま。
関心ごと
ELFのインタプリタはld-linux.so
man execveを読めってことでした。
実行ファイルが動的リンクされた a.out 実行形式で、共有ライブラリの スタブを含むものだった場合、実行の開始時に Linux の ダイナミックリンカー ld.so(8) が呼び出され、必要な共有ライブラリをメモリーに読み込んでリンクを行う。
実行ファイルがダイナミックリンクされた ELF 実行形式だった場合、 PT_INTERP セグメントに指定されたインタープリターが必要な 共有ライブラリ (shared library) を読み込むのに使用される。 通常、インタープリターは glibc をリンクしたバイナリでは /lib/ld-linux.so.2 である。
__libc_start_main は動的にロードされる
そのため開始前にはアドレスが決まらない。 言及しているエントリがあった。 そのまえに、nmでシンボルを確認しろよって話でした。
|
|
main の呼び出し箇所の確認
解説記事と異なりx86_64環境だけど確認してみた。
__libc_start_main
の最初の引数がmain
へのポインタになってた。ただpushじゃなくて%rdi
を使っている。
|
|
main関数から外はバックトレースで見えない
この記事でmainに入るときはフレームポインタ(%ebp
(64bitだと%rbp
))をスタックに積むなどの事前処理を行わないためmainの内外が分離されることが書かれてた。
スタックに呼び元の情報が記録されないのだとすると%rbp
,%rsp
がどう修復されるのかわからない(もともと使ってないから不要なのかも)。
ちゃんとStack layoutやret
命令がどう動くか確認する必要がありそう。
return address of main
がmain
呼び出し前の%rip
に対応しret
命令で復帰するので実行に問題はない。
だけどmain
の外側に戻って即座にバックトレースが取得できることは解せない。