『extern で外部関数定義をすると、「ポインタ」的なものが生成される』という話が出てきて、 んん?と思ったので gcc で挙動を確認する。
環境
下記環境で動作確認を行った。
- OS: Windows10 Pro
- MSYS2
- gcc.exe (Rev1, Built by MSYS2 project) 7.2.0
多分 pacman -S base-devel
で環境一式そろうはず...。
extern を使ったコードの作成
■ main.c
#include <stdio.h>
extern int impl_func();
void echo(char* str) {
printf(str);
}
int main(int argc, char* argv[]) {
echo("Hello, World!");
impl_func();
return 0;
}
■ impl.c
int impl_func() {
return 1;
}
ビルド
コンパイル
$ gcc -c main.c -o main.o
$ gcc -c impl.c -o impl.o
リンク
$ ld -plugin C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/liblto_plugin-0.dll -plugin-opt=C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/lto-wrapper.exe -plugin-opt=-fresolution=C:\msys64\tmp\ccLHLsgf.res -plugin-opt=-pass-through=-lmingw32 -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_eh -plugin-opt=-pass-through=-lmoldname -plugin-opt=-pass-through=-lmingwex -plugin-opt=-pass-through=-lmsvcrt -plugin-opt=-pass-through=-lpthread -plugin-opt=-pass-through=-ladvapi32 -plugin-opt=-pass-through=-lshell32 -plugin-opt=-pass-through=-luser32 -plugin-opt=-pass-through=-lkernel32 -plugin-opt=-pass-through=-lmingw32 -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_eh -plugin-opt=-pass-through=-lmoldname -plugin-opt=-pass-through=-lmingwex -plugin-opt=-pass-through=-lmsvcrt -m i386pep -Bdynamic -o main.exe C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/../../../../x86_64-w64-mingw32/lib/../lib/crt2.o C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/crtbegin.o -LC:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0 -LC:/msys64/mingw64/bin/../lib/gcc -LC:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/../../../../x86_64-w64-mingw32/lib/../lib -LC:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/../../../../lib -LC:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/../../../../x86_64-w64-mingw32/lib -LC:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/../../.. main.o impl.o -lmingw32 -lgcc -lgcc_eh -lmoldname -lmingwex -lmsvcrt -lpthread -ladvapi32 -lshell32 -luser32 -lkernel32 -lmingw32 -lgcc -lgcc_eh -lmoldname -lmingwex -lmsvcrt C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/../../../../x86_64-w64-mingw32/lib/../lib/default-manifest.o C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/crtend.o
比較
シンボルテーブル
特別なシンボルは増えていないようだ。
extern
で impl_func
関数を外部定義参照した main.o
は、 シンボル impl_func
が未定義となる。
リンク時点で未定義シンボルのアドレス解決が行われ、 main.o
の時点では未定義だったアドレスが設定されるということらしい。
$ nm main.o
0000000000000000 b .bss
0000000000000000 d .data
0000000000000000 p .pdata
0000000000000000 r .rdata
0000000000000000 r .rdata$zzz
0000000000000000 t .text
0000000000000000 r .xdata
U __main
0000000000000000 T echo
U impl_func
000000000000001c T main
U printf
$ nm impl.o
0000000000000000 b .bss
0000000000000000 d .data
0000000000000000 p .pdata
0000000000000000 r .rdata$zzz
0000000000000000 t .text
0000000000000000 r .xdata
0000000000000000 T impl_func
$ nm main.exe | grep impl_func
00000000004015c0 T impl_func
うーん、これで extern の挙動分かったつもりになったけど、 把握するうえでこれ以外に情報は必要だろうか?
とりあえず調べた内容は残しておく。