歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> Linux技術

linux g++ 鏈接器

我們都知道,要把源代碼變成可以運行的程序,需要經過編譯、鏈接等步驟。
其中編譯步驟很好理解,就是把我們寫的高級語言程序變成機器能夠理解的機器指令的過程。
那麼既然已經機器指令了,為什麼還需要鏈接才能運行呢?鏈接究竟做了什麼?怎麼做的?
這就是我們今天的主題。

基礎概念

linux g++ 鏈接器(一)基礎概念

一個實驗

請看這樣四個文件:
head.h
[code]#include <iostream>
using namespace std;
void myfun();

main.cpp
[code]#include "head.h“
int main()
{
    myfun();
    return 0;
}

a.cpp
[code]#include "head.h“
void myfun()
{
    cout<<"myfun in a.cpp"<<endl; 
}

b.cpp
[code]#include "head.h“
void myfun()
{
    cout<<"myfun in b.cpp"<<endl; 
}

把這四個文件生成目標文件並鏈接到一起會怎樣呢?為什麼?
A. 鏈接錯誤
B. 打印“myfun in a.cpp”
C. 打印“myfun in b.cpp”
D. 看情況
源代碼可以編譯成三種目標文件,不同目標文件之間的鏈接方法不同,結果也不同。讀完後面的內容,就能明白其中的道理。

可重定位目標文件的鏈接

可重定位目標文件的鏈接

靜態庫的鏈接

靜態庫可以簡單看作是一組可重定位文件的打包。
雖然鏈接命令中是把所有文件打包拿來的,但不是每個文件都真的用得到。
鏈接靜態庫和鏈接可執行文件相比,只是多了一步篩選文件的動作。

在鏈接開始之前,鏈接器會維持兩份表,一份記錄已定義的符號,另一份記錄未定義的符號。
鏈接器會先把靜態鏈接器拆包,然後一一篩選。只有當前未定義符號的表中符號且能被那個文件能提供,文件才會被留下來。其它的文件都會被扔掉。
篩選剩下的文件與其它的可重定位文件一起,進入後面的靜態鏈接過程。
靜態鏈接過程與可重定位文件的靜態鏈接過程完全一致。分為文件合並、地址分配和重定位三個步驟,以及happy endding、one-on-one和符號缺失三種鏈接結果。
上文的例子中,如果先鏈接a.o生成的liba.a,那麼libb.a中的b.o就會被扔掉。
只有main.o和a.o鏈接,所以鏈接器不會報錯而鏈接a.o中的符號。

共享目標文件的鏈接

共享目標文件的鏈接
Copyright © Linux教程網 All Rights Reserved