首先,從程式到可執行程式要經過如下幾個步驟:
在彙編結束之後,就已經生成了二進位制的可執行檔案。這次我們主要介紹符號解析這一步。
符號解析
符號解析:將每個模組中引用的符號(符號引用)與某個目標模組的定義符號(符號定義)建立關聯。
簡單理解就是比如在某處呼叫了乙個函式fun()。這個fun就可以看做是其符號引用,fun函式的定義可以看做是符號定義。然後符號解析就是把這個符號引用fun與他的函式定義(符號定義)連線起來,也就是建立起乙個對映關係,用符號表來記錄這個對映關係。
為什麼呢?因為每個定義符號在**段(函式)和資料段(變數)都分配了儲存空間,這樣經過符號解析之後
看乙個例子:
main.c
int a[3] = ;
void fun1()
int main()
gcc -c main.c -o main.o
生成可重定位檔案
然後用readelf -s main.o
看到符號表如下:
可以看到main函式的節數也就是ndx 就是1說明他是在可重定位檔案的第一節,以及fun1函式也是在1,這就是有符號定義的符號,對比來看fun符號ndx是und就是undefine,就是沒有定義的意思。fun1 fun main這幾個符號的作用域都是全域性作用域
強符號,弱符號
強符號:有函式的定義函式名和已初始化的全域性變數名
弱符號:沒有函式的定義的函式宣告以及未初始化的全域性變數名
很好理解:
test1.c
int a;//弱符號
int b = 1;//強符號
void p();//弱符號
void fun()
int main()
弱乙個符號被定義為一次強符號和多次若符號,則按強定義為準objcopy
有乙個objcopy命令就非常有意思了:
objcopy [option] [infile] [outfile]
他有乙個選項:-w
-w symbolname, --weaken-symbol=symbolname
將指定符號變為弱符號。該選項可以多次指定
-w能幹什麼呢?可以在不被別人發現的情況下(也就是不該別人的源**),將別人的函式偷換成你的實現。這種技術有時候在公司的專案會用到,這樣可以避免修改太多源**,要做的是寫乙個shell指令碼檔案就行了。
我們只要把函式原來的符號定義(原來的強符號)弱化即可,這樣這個函式的所有符號引用(弱符號)就會以我們自己寫的符號定義(強符號)為準。
舉個例子:
源** main.c
#include void f1()
int main()
我想講f1的函式實現給換掉,我就可以寫乙個swap.c
#include void f1()
然後操作他們的.o檔案 對符號引用做手腳
gcc -c main.c -o main.o
gcc -c swap.c -o swap.o
objcopy -w f1 main.o
gcc main.o swap.o -o main
執行可執行檔案
會輸出this is my f1.
說明函式定義已經被替換.
他還有以下功能:
--redefine-sym old=new
變更符號名稱。當鏈結兩個目標檔案產生符號名稱衝突時,可以使用該選項來解決
可以直接修改符號引用,這個功能順路介紹一下,因為和符號相關。他可以將乙個函式的符號變更為另乙個符號。
例子:還是main.c,將f1符號定義刪除
int main()
修改swap.c,重新起乙個名字f2.
#include void f2()
直接編譯肯定會出錯,因為f1沒有對應的符號定義,這個時候我們可以在不改變main.c的源**的情況下修改f1的符號為f2
首先:
gcc -c main.c -o main.o
gcc -c swap.c -o swap.o
然後,讓f1符號引用變更為f2
objcopy --redefine-sym f1=f2 main.o
最後鏈結並執行
gcc main.o swap.o -o main
./main
輸出 this is my f 鏈結之符號解析
之前寫過一篇部落格講述了鏈結的來由 這篇部落格則打算講講鏈結的核心工作 符號解析和重定位。看這篇部落格之前可能需要一點基礎,大家可以先看看我上面的鏈結的文章,再來看這篇。什麼是符號解析?符號解析分為區域性符號解析和全域性符號解析,區域性的不用說。全域性符號解析因為多個目標檔案可能會定義相同的名字的全...
鏈結時出現無法解析的外部符號排錯
鏈結時出現 無法解析的外部符號,錯誤資訊 cpp編譯出的符號 batviewdlg.obj error lnk2001 unresolved external symbol unsigned char stdcall getpwrcapabilities struct system power ca...
鏈結器,符號解析與重定位 概念
符號解析。將每個符號引用剛好和乙個符號定義聯絡起來。符號分為四類 匯出符號 export,本地符號 匯入符號 import,外部符號 靜態符號 本地符號 區域性符號 本地符號,不出現在符號表中 匯出符號,在本模組定義,能夠被其他模組引用的符號。非static全域性函式,非static全域性變數。匯入...