
以下の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>の最初の命令を呼び出していたのですが、
何故、この様な出力になってしまったのか分かりかねています。
どなたか分かる方、御教示おください。
No.3ベストアンサー
- 回答日時:
オブジェクトファイルを逆アセするんじゃなくって, gcc に直接アセンブリ出力を出させれば 3つのうち 1つは意味がわかる.
あと, 自分で調べることも必要だと思う.
調べてみたんですけど、gccはデフォルトで、-O0オプションとなるようで、
この場合、コンパイラが「位置に依存しない」実行可能ファイルを生成するみたいです。
call __x86.get_pc_thunk.ax
はそのための「グローバルポインタ」を設定するためのものの様です。
これは、
-fno-pie
オプションをつけることで、位置に依存しない形で無くすことができる様です。
また、callの後の、
add $0x8, %esp
はfuncのスタックフレームの上限のスタックポインタの位置を仮引数を渡すために使った、5と7の2個はもう必要ないので、+8しているみたいです。
No.5
- 回答日時:
うん, そこの
fc ff ff ff
は現状「バイトを埋める」だけのダミーで, 最終的にはその飛び先である関数 add の先頭アドレス (の相対値) が入ることになる. それを入れるのはリンカかローダーのどっちかなんだけど, この場合どっちなんだろう.
そもそも同じオブジェクトファイルの中で呼んでいるだけだから, そこをダミーにする必然性はないわけだけど.
あと, 念のため改めて書いておくけどこの辺の話は C という言語とは関係なくって, 使っているシステムに依存することだからね. ここではたまたまあなたが C を使っていて疑問に思ったというだけであって, 「C だったらどのシステムでも同じようになっている」というわけではないよ.
No.4
- 回答日時:
「デフォルトで最適化オプション -O0 がつく」ことと「PIC なコードを吐く」こととは無関係だよ. -O0 以外の最適化オプショ
ンでも, -fno-pie オプションを付けないと PIC なコードになる.call 35 <func+0x15>
って、この位置のfc ff ff ffに
<add>の飛び先番地が入るってことなのですかね?
No.2
- 回答日時:
そこまで細かい話は当然ながら C の規格では一切触れられていないので, 本当に理由を知りたければ最低限「あなたが使っているシステムの詳細」は必須だろう. 「以前」のシステムはどうであって, 「今」のシステムはどうなのか, その情報がなければ答えようがない.
もちろんそれらの情報があれば確実に (誰かが) 答えてくれる, というものでもないわけだが.
あるいは, オブジェクトファイルを使わず gcc にアセンブリ出力を直接出させてみるとか.
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
DLLファイルの逆コンパイラにつ...
-
卒業研究でよく分からないとこ...
-
プログラマー達は何故、プログ...
-
プログラミングc++を全く分か...
-
c言語
-
C++でデスクトップGUIアプリ開...
-
C言語の質問です。バイナリ形...
-
C言語について。
-
ストリームについて。
-
逆コンパイルと逆アセンブルの...
-
gccを行ってもexeファイルが生...
-
VisualStudioでC++クラスを追加...
-
c言語でイベントフラグを使った...
-
大量のデータを読み込んで表示...
-
C言語について(初心者)
-
UART通信の取説で,left floati...
-
C#でTreeViewのCheckBoxのサイ...
-
MACで動く実行ファイルをWindow...
-
Cのコンパイルでコメントアウト...
-
C言語でファクト関数を使わずに...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
c言語
-
DLLファイルの逆コンパイラにつ...
-
Windows Formアプリからコンソ...
-
大量のデータを読み込んで表示...
-
C言語の関数のextern宣言
-
VisualStudioでC++クラスを追加...
-
【C言語】全角文字の配列を、全...
-
VisualStudio2022でC言語プログ...
-
C++でデスクトップGUIアプリ開...
-
gccを行ってもexeファイルが生...
-
C#でTreeViewのCheckBoxのサイ...
-
C#でログファイルにファイルパ...
-
プログラマー達は何故、プログ...
-
逆コンパイルと逆アセンブルの...
-
Notepad++の関数リスト表示の変...
-
C言語について。
-
Cのコンパイルでコメントアウト...
-
visual studio 2022でのC#プロ...
-
コンソールアプリを作成するの...
-
C言語 バッファについて。
おすすめ情報
リリースモードでコンパイルした場合、
gcc -c -m32 funcTest.c
はどの様に書けばいいのでしょうか?
3つのcall命令は何をしているか分かりますか?
それは既にやっているのですが、
何故、最後の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
も何をやっているんでしょうね?