外部リンケージがあるかのように main を宣言する必要があるのはなぜですか?
なぜ静的であってはならないのですか?
外部リンケージとはどういう意味ですか??
起動ファイルをプログラムにリンクするためです。このプログラムには、(通常は) メインを呼び出すアセンブラー コードが含まれています。メインが静的である場合、そのコードはメインを呼び出すことができません。
external linkage
他のいわゆるtranslation-units
は、独自の翻訳単位で extern 宣言されたシンボルを見ることができることを意味します。したがって、メインは extern であり、そのアドレスを示す変換単位シンボル テーブルにエントリがあります。他の変換単位は、main を呼び出したいときにそのアドレスにジャンプできます。
static linkage
は、シンボルが厳密に翻訳単位ローカルであることを意味します。これは、他の人translation units
がそのシンボルを見ることができないことを意味します。したがって、静的リンケージを持つシンボルは、異なる翻訳単位で複数回発生する可能性があり、ローカルであるため互いに衝突することはありません。
編集:一般に、翻訳単位からコンパイラによって生成されたファイルは、その特定のコンパイラに固有です。Linux 上の gcc では、多くの場合、ELF オブジェクト形式が使用されます。以下を使用してシンボル テーブルを表示できますreadelf -sW <file>.o
(以下の簡単なテスト ファイル)。
test.c
void bar(void);
static int foo(void) {
return 1;
}
int main(void) {
bar();
return foo();
}
readelf の出力は次のとおりです。
Symbol table '.symtab' contains 10 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 0 FILE LOCAL DEFAULT ABS test.c
2: 00000000 0 SECTION LOCAL DEFAULT 1
3: 00000000 0 SECTION LOCAL DEFAULT 3
4: 00000000 0 SECTION LOCAL DEFAULT 4
5: 00000000 10 FUNC LOCAL DEFAULT 1 foo
6: 00000000 0 SECTION LOCAL DEFAULT 6
7: 00000000 0 SECTION LOCAL DEFAULT 5
8: 0000000a 36 FUNC GLOBAL DEFAULT 1 main
9: 00000000 0 NOTYPE GLOBAL DEFAULT UND bar
main 関数と、main によって呼び出される static foo 関数が表示されます。また、ファイルで定義されていないが、別のオブジェクトファイルで定義されている関数が呼び出されています。オブジェクト ファイルがまだ最終的にリンクされていないため、関数にはまだ最終的なアドレスが割り当てられていません。最後のリンクの後、これらは実行可能ファイルに配置され、アドレスが割り当てられます。オブジェクト ファイルには、まだ定義されていない関数への呼び出しのエントリが含まれているため、ファイルがリンクされると、それらの呼び出し命令に最終的なアドレスが格納されます ( readelf -r <file>.o
)。
Relocation section '.rel.text' at offset 0x308 contains 1 entries:
Offset Info Type Sym.Value Sym. Name
0000001c 00000902 R_386_PC32 00000000 bar
コードの実際の開始点は、C ランタイム ライブラリに埋もれています。このランタイム ライブラリは、main() ルーチンを呼び出します。リンカが C RTL 呼び出しを main() 関数に接続するためには、ファイルの外部で可視である必要があります。
外部リンケージはまさにこれです: 問題の名前がオブジェクト ファイルのエクスポートの一部として表示されることを意味します。リンカの仕事は、未処理のインポートがないように、すべてのインポートとエクスポートを結合することです。