http://blog.chinaunix.net/uid-25714468-id-5557081.html
鏈接器必須對這些可重定位目標文件完成兩個主要任務:
- 符號解析。將每個符號引用剛好和一個符號定義聯系起來。
- 重定位。鏈接器把每個符號定義與一個虛擬地址聯系起來,然后修改所有對這些符號的引用,使得它們指向這個存儲位置,從而重定位這些節。
符號分為四類: 導出符號(export,本地符號), 導入符號(import,外部符號), 靜態符號(本地符號), 局部符號(本地符號,不出現在符號表中)。
導出符號, 在本模塊定義, 能夠被其他模塊引用的符號。 非static全局函數, 非static全局變量。
導入符號, 在其他模塊定義,被本模塊引用的符號。 extern 修飾的全局非static變量聲明(extern int a), 其他模塊的函數引用
靜態符號, 在本模塊定義, 只能被本模塊引用的符號。 static函數, static全局變量。
局部符號, 在函數內部定義的非static變量。不出現在符號表,由棧管理。鏈接器不care這類符號
外部符號(導入符號): 本模塊未定義卻被本模塊引用的符號。
匯編器生成可重定位目標文件后, 內部符號都已被正確地符號解析, 外部符號可能會引用了非本模塊的符號定義,匯編器無法找到符號定義, 因此無法解析。 匯編器把外部符號放入”符號表“.symtab,同時把如何解析該符號的方法放入”重定位表“。
鏈接器符號解析:
使用的表: 符號表
強符號,若符號: 函數和初始化的全局變量叫強符號, 未初始化的全局變量叫弱符號。(extern int a是一個弱符號定義, int a 也是弱符號)
符號解析規則:
1, (定義多個強符號) 當引用符號時,該符號的符號定義有不止一個強符號定義時,會出現符號重定義錯誤。
2, (定義一個強符號和一個或者多個軟符號)當引用符號時, 該符號的符號定義有個強符號定義和一個和多個弱符號定義, 使用強符號定義。
3, (定義多個弱符號)當引用符號時, 該符號的符號定義都是弱符號時, 選擇任意一個定義。
鏈接器符號重定位:
使用的表: 重定位表,符號表
重定位表記錄要修改的符號引用的位置,以及如何修改。
一旦鏈接器完成了符號解析這一步,它就把代碼中的每個符號引用和確定的一個符號定義聯系起來。此時,鏈接器就知道了每個模塊(文件)代碼節和數據節的大小,就可以開始重定位了。
重定位由三步組成:
- 合並可重定位目標文件中相同的節,
- 重定位節和符號定義,修改符號表。為節和符號定義分配虛擬地址。修改符號表中符號定義的值為剛分配的虛擬地址。
- 重定位節中的符號引用,修改代碼段和數據段符號引用。使用重定位表.rel.text .rel.data, 修改text,data中符號引用的地址
簡述為, 合並節, 重定位符號定義(修改符號表),重定位符號引用(修改數據段代碼段)
匯編器遇到對存儲位置未知(在可重定位目標文件中,匯編器都不知道數據和代碼會存放在存儲器的什么位置)的符號引用時,它也會將這些符號的信息存於.rel.text和.rel.data表中。告訴鏈接器將可重定位目標文件合並成可執行目標文件時如何修改符號引用。
