VisualStadioでのコンパイルとリンクの結果を見てみる。
extern int ExternFunction(void);/*外部関数のプロトタイプ宣言*/ extern int ExternValue;/*外部変数の宣言*/ static int StaticFunction(void)/*内部結合の関数*/ { return 1; } int main(void) { static int s=2;/*静的変数かつ局所変数*/ int ret;/*自動変数かつ局所変数*/ ret=StaticFunction(); ret+=ExternValue; ret+=ExternFunction(s); return ret; } int ExternFunction(int s)/*外部結合の関数*/ { return 2*s; } int ExternValue = 5;/*外部結合の大域変数*/
main関数内の自動変数はすでにアドレスとの対応付けが行われているが,静的変数と関数については名前のみが記録され,アドレス部分は0で埋められていることが分かる。
※main関数の局所的な静的変数sもアドレスは未定で,リンクでアドレスと対応付けされる。このstaticな局所変数と内部変数を同じ静的メモリ領域に割り当てているので,リンクまでアドレスが決まらないのが原因だろうか?
RAW DATA #3 00000000: 05 00 00 00 02 00 00 00 <<静的変数 ExternValue と s _ExternFunction: 00000000: 55 push ebp 00000001: 8B EC mov ebp,esp 00000003: 8B 45 08 mov eax,dword ptr [ebp+8] 00000006: D1 E0 shl eax,1 00000008: 5D pop ebp 00000009: C3 ret _StaticFunction: 00000010: 55 push ebp 00000011: 8B EC mov ebp,esp 00000013: B8 01 00 00 00 mov eax,1 00000018: 5D pop ebp _main: 00000020: 55 push ebp 00000021: 8B EC mov ebp,esp 00000023: 51 push ecx 00000024: E8 00 00 00 00 call _StaticFunction <<結合前でアドレスは0で埋めている 00000029: 89 45 FC mov dword ptr [ebp-4],eax <<mainの自動変数retのアドレスはebp-4 0000002C: 8B 45 FC mov eax,dword ptr [ebp-4] 0000002F: 03 05 00 00 00 00 add eax,dword ptr [_ExternValue] 00000035: 89 45 FC mov dword ptr [ebp-4],eax 00000038: 8B 0D 00 00 00 00 mov ecx,dword ptr [?s@?1??main@@9@9]<<mainの局所変数sのこと 0000003E: 51 push ecx 0000003F: E8 00 00 00 00 call _ExternFunction 00000044: 83 C4 04 add esp,4 00000047: 03 45 FC add eax,dword ptr [ebp-4] 0000004A: 89 45 FC mov dword ptr [ebp-4],eax 0000004D: 8B 45 FC mov eax,dword ptr [ebp-4] 00000050: 8B E5 mov esp,ebp 00000052: 5D pop ebp 00000053: C3 ret
長いので関係の薄い部分は省いている。
リンクにより結合結果を代入して,オブジェクトでは名前であった部分が,実行可能ファイルではアドレスに書き変わっている。
............................................... 00401000: 55 push ebp 00401001: 8B EC mov ebp,esp 00401003: 8B 45 08 mov eax,dword ptr [ebp+8] 00401006: D1 E0 shl eax,1 00401008: 5D pop ebp 00401009: C3 ret ............................................... 00401010: 55 push ebp 00401011: 8B EC mov ebp,esp 00401013: B8 01 00 00 00 mov eax,1 00401018: 5D pop ebp 00401019: C3 ret .............................................. 00401020: 55 push ebp 00401021: 8B EC mov ebp,esp 00401023: 51 push ecx 00401024: E8 E7 FF FF FF call 00401010 <<call命令の機械語は相対アドレスで負の値 00401029: 89 45 FC mov dword ptr [ebp-4],eax 0040102C: 8B 45 FC mov eax,dword ptr [ebp-4] 0040102F: 03 05 00 30 41 00 add eax,dword ptr ds:[00413000h] 00401035: 89 45 FC mov dword ptr [ebp-4],eax 00401038: 8B 0D 04 30 41 00 mov ecx,dword ptr ds:[00413004h] 0040103E: 51 push ecx 0040103F: E8 BC FF FF FF call 00401000 00401044: 83 C4 04 add esp,4 00401047: 03 45 FC add eax,dword ptr [ebp-4] 0040104A: 89 45 FC mov dword ptr [ebp-4],eax 0040104D: 8B 45 FC mov eax,dword ptr [ebp-4] 00401050: 8B E5 mov esp,ebp 00401052: 5D pop ebp 00401053: C3 ret .............................................. 00413000: 05 00 00 00 02 00 00 00 FF FF FF FF 01 00 00 00 <<静的変数 ExternValue と s
call命令の跳び先は機械語では相対アドレスで記述されているので負の値になっている。
アセンブラではこれを絶対アドレスに換算して示してくれている。
00401024: E8 E7 FF FF FF call 00401010 00401029: 89 45 FC mov dword ptr [ebp-4],eax
call命令の次の機械語の番地00401029を基準としてFFFFFFE7を加算すると桁あふれした部分を無視すれば
00401010となる
※上位のバイトは上位の番地に格納する方式なので「E7 FF FF FF 」の値はFFFFFFE7