コマンドラインから直接 gcc を起動するような場合、いつも無意識のうちに -g -O0 とオプションを付けとりますな。多分バグをこさえて デバッガ のお世話になるだろうから。それに最適化の効いたオブジェクトをスラスラ読めるほどデキる人でもあるまいし。今回は -g して生成される「もの」を遠くから眺めてみるの回。
※「オプション沼」投稿順 index はこちら
※以下実験はWindows11上のWSL2で動作しているUbuntu 20.04LTSで行ってます。gccのバージョンは9.4.0です。
「いつもの」 -g オプションと -O0 オプション
最近ではIDEとか、VScodeエディタのプラグインなどが世話を焼いてくれるので、gcc(あるいはclang) や gdb を直接呼び出さないことが多いじゃないかと思います。
-
- -g、gdbで読み込めるデバッグ用のシンボルをオブジェクトファイルに含める
- -O0、gcc(cc1)でコンパイル時に最適化しない
上記のオプションは、デバッグするときには必須(別に最適化されたコードをちゃきちゃきデバッグできるならば -O0 でなくて、-O2でも -O3でもよいです。)
-g はいつもお世話になっている割に、オブジェクトコードの中に何を詰めてくれているのかイマイチです。せめてセクション名くらい知っておきたいという野望?(小さい望みだな、自分)で、前回もモルモットに使ったソースを -g 付と-g無の両方でコンパイルしてみましたぜ。こんな感じ。
gcc -g -O0 -o with_g root2.c -lmpfr -lgmp gcc -O0 -o wo_g root2.c -lmpfr -lgmp
1行目の方でできるオブジェクト with_g ならデバッグ可能。gdbを呼び出すとこんな感じ。
そして、ブレークポイントを設定して走らせてみる、と。こんな感じ。
ま、無事にブレークポイントで止まるようです。
一方、-gオプションを付けずにコンパイルした wo_g の方をgdbに渡してみると、こんな感じ。以下の黄色い線のところ、デバッグ・シンボルが無いじゃないかと怒られます。当然か。
まずはセクション・レベルで比較してみる
生成されたオブジェクトコードがどうなっているのか、まずはセクション・レベルで比較してみることにいたしました。これのため、御出馬いただくのが
objdump
であります。binutilの中の地味な一品ですが、オブジェクトコードの中身を見るためには欠かせぬ名わき役とな。ホントか?
ただ、objdumpに渡すオプションによってはやたら大量の出力がでてきて「メンドイ」のも事実。objdump -h で、セクション・ヘッダを「だけ」を列挙してみます。これなら出力行数も少ないし。こんな感じ。
objdump -h with_g >objdump_h_with_g.lst objdump -h wo_g >objdump_h_wo_g.lst
上記で得られた二つのファイルを伝統のmc(midnight commander)で比較したところが以下に。Windows11のTerminalはWSL2のLinuxのシェルウインドウを簡単に開ける上、mcはマウスポインタにも反応するので、CUIで作業するときはとてもお楽。
左がwo_gのデバッグオプション無の方で、右がwith_gのデバッグオプション付きです。右で緑色になっている5つのセクションが、左側では不在(赤)だと。
5つのセクション名を列挙すると以下の通り。
-
- .debug_aranges
- .debug_info
- .debug_abbrev
- .debug_line
- .debug_str
さて、これらセクションの中身がチト気になります。深みにハマらないように、とりあえずダンプする方法だけを確かめておきます、今回は。
なんと、objdumpにも -g というそのものズバリのオプションがあったのね。いかに使えてないかがわかるというもの。objdump に -g つけて動かせば、
$ objdump -g with_g
どっと上記のデバッグセクションの内容(それ以外の関係セクションも含む)がダンプされます。せっかくダンプしたけれど、今回は中に踏み込むのやめとこ。。。