
以下の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で質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# アセンブラ指令 3 2023/06/17 14:47
- その他(プログラミング・Web制作) x86_32のGASの擬似命令 3 2023/06/07 19:55
- C言語・C++・C# スタックフレームの消滅 6 2023/05/20 12:33
- JavaScript アップロードファイルの種類によって処理を分岐させたいのですが書き方が分からずアドバイスお願いします 4 2023/06/17 19:12
- C言語・C++・C# C言語の課題が出たのですが自力でやっても分かりませんでした。 要素数がnであるint型の配列v2の並 3 2022/11/19 17:41
- オープンソース stable diffusionのインストールがうまくいきません。 1 2023/06/20 13:09
- その他(プログラミング・Web制作) python 2 2022/12/23 09:06
- C言語・C++・C# C言語 ポインタ 配列 2 2022/06/02 17:29
- Visual Basic(VBA) 【Excel VBA】自動メール送信の機能追加 5 2022/09/29 12:53
- その他(ソフトウェア) Microsoft Store Guitar Pro購入後の質問 1 2022/08/11 17:15
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
Windows Formアプリからコンソ...
-
visual studio 2022でのC#プロ...
-
C言語をコンパイルするとコンピ...
-
大量のデータを読み込んで表示...
-
c言語でイベントフラグを使った...
-
略語の読み方について
-
逆コンパイルと逆アセンブルの...
-
C# でソフト開発をした事のある...
-
C言語関数違いについて。
-
C#でTreeViewのCheckBoxのサイ...
-
[C言語]fputsとfprintfの違い
-
c言語
-
VisualStudio2022でC言語プログ...
-
C++でデスクトップGUIアプリ開...
-
Notepad++の関数リスト表示の変...
-
gccを行ってもexeファイルが生...
-
Linuxでの開発環境構築や設定の...
-
c#のTLS1.2での通信について
-
【C言語】全角文字の配列を、全...
-
C言語の関数のextern宣言
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
プログラマー達は何故、プログ...
-
C言語の関数のextern宣言
-
Windows Formアプリからコンソ...
-
大量のデータを読み込んで表示...
-
PIC12F1822でLED調光器を作りたい
-
最初に聞かれたこと
-
C言語について(初心者)
-
C言語 関数、変数の宣言について
-
VisualStudioでC++クラスを追加...
-
C#でログファイルにファイルパ...
-
【C言語】全角文字の配列を、全...
-
逆コンパイルと逆アセンブルの...
-
VisualStudio2022でC言語プログ...
-
c#のTLS1.2での通信について
-
int16_t の _t は何?
-
c言語
-
バッチファイルで以下のような...
-
gccを行ってもexeファイルが生...
-
C++でデスクトップGUIアプリ開...
-
C#でTreeViewのCheckBoxのサイ...
おすすめ情報
リリースモードでコンパイルした場合、
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
も何をやっているんでしょうね?