C言語の「Hello World!」プログラムで使われる、「printf()」「main()」関数の中身を、デバッガによる解析と逆アセンブル、ソースコード読解などのさまざまな側面から探る連載。今回は、printf()内のポインタ経由での関数呼び出しが行き着く先を試行錯誤のデバッグで探る。
書籍の中から有用な技術情報をピックアップして紹介する本シリーズ。今回は、秀和システム発行の書籍『ハロー“Hello, World” OSと標準ライブラリのシゴトとしくみ(2015年9月11日発行)』からの抜粋です。
ご注意:本稿は、著者及び出版社の許可を得て、そのまま転載したものです。このため用字用語の統一ルールなどは@ITのそれとは一致しません。あらかじめご了承ください。
※編集部注:前回記事「「Hello World!」の主役printf()の内部動作をデバッガGDBで追う」はこちら
現在はstepiによって関数呼び出しをした後でlayout asmでアセンブラ表示に切替えたため、呼び出し前の状態を見ることができていない。
layout asmを指示した状態で、もう一度やりなおしてみよう。デバッガでのデバッグはこのように、何度もやりなおして探ることで感覚をつかんでいくといいかと思う。
ということでrunによってプログラムを再実行する。実行中の状態で再実行しているので「最初から実行するか?」と聞いてくるが、「y」を選択する。
(gdb) run The program being debugged has been started already. Start it from the beginning? (y or n) Starting program: /home/user/hello/hello Breakpoint 1, main (argc=1, argv=0xbffffc14) at hello.c:5 (gdb)
画面は図2.8のようになった。main()の先頭でブレークしているのだが、アセンブラ表示の状態でブレークしているだろう。なお画面が崩れて「Hello World!」の表示が残ってしまっている場合には、Ctrl+Lで適宜画面をリフレッシュすることができる。
反転表示されている行を見ると、どうやら「mov 0xc(%ebp),%eax」という命令でブレークしているようだ。
まずはステップ実行によって、動作を進めてみよう。stepiを一回、実行してみる。
(gdb) stepi
すると図2.9のように、実行が1命令進んだ。
さらにstepiを繰り返し実行し、「call」という命令まで進めてみよう。
callという命令の位置で停止している。これは、x86の関数呼び出し命令だ。
もう一度、stepiを実行してみよう。
(gdb) stepi 0x08049360 in printf () (gdb)
呼び出し先の関数の中に入ったようだ。左から2列目の表示が「<printf>」に切り替わった点に注目してほしい。つまり今は、printf()の先頭で停止していることになる。
stepiで、処理を進めてみよう。
(gdb) stepi 0x08049361 in printf () (gdb)
関数の中でも、stepiによるステップ実行は問題無く行えるようだ。
Copyright © ITmedia, Inc. All Rights Reserved.