試行錯誤のデバッグで探る、printf()内のポインタ経由での関数呼び出しが行き着く先とはmain()関数の前には何があるのか(3)(1/4 ページ)

C言語の「Hello World!」プログラムで使われる、「printf()」「main()」関数の中身を、デバッガによる解析と逆アセンブル、ソースコード読解などのさまざまな側面から探る連載。今回は、printf()内のポインタ経由での関数呼び出しが行き着く先を試行錯誤のデバッグで探る。

» 2017年06月01日 05時00分 公開
[坂井弘亮]

連載目次

ハロー“Hello,World” OSと標準ライブラリのシゴトとしくみ

書籍の中から有用な技術情報をピックアップして紹介する本シリーズ。今回は、秀和システム発行の書籍『ハロー“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で適宜画面をリフレッシュすることができる。

図2.8: layout asmの状態でブレークする 図2.8: layout asmの状態でブレークする

 反転表示されている行を見ると、どうやら「mov 0xc(%ebp),%eax」という命令でブレークしているようだ。

 まずはステップ実行によって、動作を進めてみよう。stepiを一回、実行してみる。

(gdb) stepi

 すると図2.9のように、実行が1命令進んだ。

図2.9: stepiを実行する 図2.9: stepiを実行する

 さらにstepiを繰り返し実行し、「call」という命令まで進めてみよう。

図2.10: call命令まで進める 図2.10: call命令まで進める

 callという命令の位置で停止している。これは、x86の関数呼び出し命令だ。

 もう一度、stepiを実行してみよう。

(gdb) stepi
0x08049360 in printf ()
(gdb)
図2.11: printf()の内部 図2.11: printf()の内部

 呼び出し先の関数の中に入ったようだ。左から2列目の表示が「<printf>」に切り替わった点に注目してほしい。つまり今は、printf()の先頭で停止していることになる。

 stepiで、処理を進めてみよう。

(gdb) stepi
0x08049361 in printf ()
(gdb)
図2.12: printf()の中でステップ実行する 図2.12: printf()の中でステップ実行する

 関数の中でも、stepiによるステップ実行は問題無く行えるようだ。

       1|2|3|4 次のページへ

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。