[英]How does the linker know where is the definition of an extern function?
我讀了幾篇帖子並得出結論,extern告訴編譯器“這個函數存在,但它的代碼在其他地方。不要驚慌。” 但鏈接器如何知道函數的定義位置。
我的案例: - 我正在研究Keil uvision 4.有一個頭文件grlib.h,主函數在grlib_demo.c(它包含grlib.h)。 現在,有一個函數GrCircleDraw()在Circle.c中定義並在grlib_demo.c中調用,還有一個語句
extern void GrCircleDraw(所有參數);
在grlib.h中。 我的查詢是鏈接器如何知道GrCircleDraw()的定義,因為Circle.c不包含在grlib.h和grlib_demo.c中
注意: - 文件grlib.h和Circle.c位於同一文件夾中。 代碼運行成功。
簡單的答案是“編譯器不需要知道,但鏈接器必須能夠找到它”。 通過多個.o
文件或通過庫,鏈接器必須能夠找到GrCircleDraw
函數的單個定義。
編譯器只將extern
函數的名稱放入.obj
文件中。 編譯器不需要了解更多信息。
當您開始鏈接時,作為開發人員,您有責任將所有必需的目標文件和庫文件提供給鏈接器。 鏈接器會將所有這些功能安排到二進制文件中。 如果您沒有指定正確的庫或.obj
文件,那么鏈接將會因unresolved blah-blah
失敗。
通常隱式包含默認庫。 這使事情復雜化並產生幻想。 您始終可以指定不需要任何隱式庫並明確包含所有內容。 不幸的是,每個系統都以自己的方式完成。
當你編譯的.o文件ELF格式 ,你對很多事情.o
文件如:
.text
部分; .data
, .rodata
, .rss
部分; .symtab
包含.o
中的符號列表(函數,全局變量等)(以及它們在文件中的位置)以及.o
文件使用的符號; .rela.text
部分,它們是重定位列表 - 這些是鏈接編輯器(和/或動態鏈接器)必須進行的修改,以便將程序的不同部分鏈接在一起。 讓我們編譯一個簡單的C文件:
extern void GrCircleDraw(int x);
int foo()
{
GrCircleDraw(42);
return 3;
}
int bla()
{
return 2;
}
有:
gcc -o test.o test.c -c
(我正在使用我的系統的本機編譯器,但在交叉編譯到ARM時它將工作完全相同)。
您可以使用以下命令查看.o文件的內容:
readelf -a test.o
在符號表中,您將找到:
Symbol table '.symtab' contains 10 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND [...] 8: 0000000000000000 21 FUNC GLOBAL DEFAULT 1 foo 9: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND GrCircleDraw 10: 0000000000000015 11 FUNC GLOBAL DEFAULT 1 bla
我們的foo
函數有一個符號, bla
有一個符號。 值字段在.text
部分中給出它們的位置。
使用的符號GrCircleDraw
有一個符號:它未定義,因為此函數未在此.o
文件中定義,但仍可在其他位置找到。
在.text
部分( .rela.text
)的重定位表中,您會發現:
Relocation section '.rela.text' at offset 0x260 contains 1 entries: Offset Info Type Sym. Value Sym. Name + Addend 00000000000a 000900000002 R_X86_64_PC32 0000000000000000 GrCircleDraw - 4
該地址在foo
:鏈接編輯器將使用GrCircleDraw
函數的地址修補此地址處的指令。
現在讓我們自己編譯一個GrCircleDraw
的實現:
void GrCircleDraw(int x)
{
}
我們來看看它的符號表:
Symbol table '.symtab' contains 9 entries: Num: Value Size Type Bind Vis Ndx Name [...] 8: 0000000000000000 9 FUNC GLOBAL DEFAULT 1 GrCircleDraw
它有一個GrCircleDraw
條目,在其.text
部分中定義它的位置。
因此,當鏈接編輯器將兩個文件組合在一起時,它知道:
.o
文件及其位置; 鏈接通常以這種方式發生:迭代命令行並給出每個參數
最后,必須完成每個參考才能成功鏈接。 鏈接器命令行中給出的行的順序很重要。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.