【3月6日実施】システムメンテナンス実施のお知らせ

以下のfuncTest.cを、

int add(int a, int b) {
int array[16];
array[0] = a;
return a + b;
}

void func(void) {
int r;
r = add(7, 5);
}

gcc -c -m32 funcTest.c
でコンパイルし、funcTets.oのオブジェクトファイルを生成し、
objdump -d funcTest.o
で逆アセンブルすると、以下の出力となるのですが、


funcTest.o: file format elf32-i386


Disassembly of section .text:

00000000 <add>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 ec 40 sub $0x40,%esp
6: e8 fc ff ff ff call 7 <add+0x7>
b: 05 01 00 00 00 add $0x1,%eax
10: 8b 45 08 mov 0x8(%ebp),%eax
13: 89 45 c0 mov %eax,-0x40(%ebp)
16: 8b 55 08 mov 0x8(%ebp),%edx
19: 8b 45 0c mov 0xc(%ebp),%eax
1c: 01 d0 add %edx,%eax
1e: c9 leave
1f: c3 ret

00000020 <func>:
20: 55 push %ebp
21: 89 e5 mov %esp,%ebp
23: 83 ec 10 sub $0x10,%esp
26: e8 fc ff ff ff call 27 <func+0x7>
2b: 05 01 00 00 00 add $0x1,%eax
30: 6a 05 push $0x5
32: 6a 07 push $0x7
34: e8 fc ff ff ff call 35 <func+0x15>
39: 83 c4 08 add $0x8,%esp
3c: 89 45 fc mov %eax,-0x4(%ebp)
3f: 90 nop
40: c9 leave
41: c3 ret

Disassembly of section .text.__x86.get_pc_thunk.ax:

00000000 <__x86.get_pc_thunk.ax>:
0: 8b 04 24 mov (%esp),%eax
3: c3 ret

以前は、
6、b行の
call 7 <add+0x7>
add $0x1,%eax
と、
26、2b行の
call 27 <func+0x7>
add $0x1,%eax
が無くて、
34、39行の
call 35 <func+0x15>
add $0x8,%esp
が、
call 0 <add>
となって、
call命令で<add>の最初の命令を呼び出していたのですが、
何故、この様な出力になってしまったのか分かりかねています。
どなたか分かる方、御教示おください。

質問者からの補足コメント

  • リリースモードでコンパイルした場合、
    gcc -c -m32 funcTest.c
    はどの様に書けばいいのでしょうか?

    No.1の回答に寄せられた補足コメントです。 補足日時:2023/05/13 07:40
  • 3つのcall命令は何をしているか分かりますか?

    No.2の回答に寄せられた補足コメントです。 補足日時:2023/05/13 17:40
  • それは既にやっているのですが、
    何故、最後のcall命令だけが、call add
    になって、それ以外の2つが、
    call __x86.get_pc_thunk.ax
    になるんですかね?

    また、__x86.get_pc_thunk.axに飛んで行っている、
    move (%esp), %eax
    って何をやっているんでしょうか?
    また、call命令を行った後の、
    addl $_GLOBAL_OFFSET_TABLE_, %eax

    addl $8, %esp
    も何をやっているんでしょうね?

    No.3の回答に寄せられた補足コメントです。 補足日時:2023/05/13 21:37

A 回答 (5件)

オブジェクトファイルを逆アセするんじゃなくって, gcc に直接アセンブリ出力を出させれば 3つのうち 1つは意味がわかる.



あと, 自分で調べることも必要だと思う.
この回答への補足あり
    • good
    • 0
この回答へのお礼

調べてみたんですけど、gccはデフォルトで、-O0オプションとなるようで、
この場合、コンパイラが「位置に依存しない」実行可能ファイルを生成するみたいです。
call __x86.get_pc_thunk.ax
はそのための「グローバルポインタ」を設定するためのものの様です。
これは、
-fno-pie
オプションをつけることで、位置に依存しない形で無くすことができる様です。
また、callの後の、
add $0x8, %esp
はfuncのスタックフレームの上限のスタックポインタの位置を仮引数を渡すために使った、5と7の2個はもう必要ないので、+8しているみたいです。

お礼日時:2023/05/14 12:06

うん, そこの


fc ff ff ff
は現状「バイトを埋める」だけのダミーで, 最終的にはその飛び先である関数 add の先頭アドレス (の相対値) が入ることになる. それを入れるのはリンカかローダーのどっちかなんだけど, この場合どっちなんだろう.

そもそも同じオブジェクトファイルの中で呼んでいるだけだから, そこをダミーにする必然性はないわけだけど.

あと, 念のため改めて書いておくけどこの辺の話は C という言語とは関係なくって, 使っているシステムに依存することだからね. ここではたまたまあなたが C を使っていて疑問に思ったというだけであって, 「C だったらどのシステムでも同じようになっている」というわけではないよ.
    • good
    • 1

「デフォルトで最適化オプション -O0 がつく」ことと「PIC なコードを吐く」こととは無関係だよ. -O0 以外の最適化オプショ

ンでも, -fno-pie オプションを付けないと PIC なコードになる.
    • good
    • 0
この回答へのお礼

call 35 <func+0x15>
って、この位置のfc ff ff ffに
<add>の飛び先番地が入るってことなのですかね?

お礼日時:2023/05/14 13:17

そこまで細かい話は当然ながら C の規格では一切触れられていないので, 本当に理由を知りたければ最低限「あなたが使っているシステムの詳細」は必須だろう. 「以前」のシステムはどうであって, 「今」のシステムはどうなのか, その情報がなければ答えようがない.



もちろんそれらの情報があれば確実に (誰かが) 答えてくれる, というものでもないわけだが.

あるいは, オブジェクトファイルを使わず gcc にアセンブリ出力を直接出させてみるとか.
この回答への補足あり
    • good
    • 0

>何故、この様な出力になってしまったのか分かりかねています。


わからないけど、前回「リリースモード」、今回「デバッグモード」でコンパイルしたとかないですか?
この回答への補足あり
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!