

Linking 鏈接
- 地址和空間的分配
- 符號(hào)解析(resolution), 符號(hào)綁定(binding)
- 重定位 (relocation)
重定位
由于每個(gè)模塊都是單獨(dú)compile出來(lái)的,比如:
main.c 調(diào)用了 foo.c中的函數(shù) foo(), 在compiler編譯main.c 的時(shí)候并不知道 foo函數(shù)的地址,所以compiler暫時(shí)將目標(biāo)地址擱置,等最后linking的時(shí)候,由linker去修正目標(biāo)地址。地址修正的過(guò)程叫做重定位,每個(gè)需要被修正的地方叫做重定位入口(relocation entry)。
鏈接與符號(hào)
在鏈接中,將函數(shù)和變量統(tǒng)稱為符號(hào) (symbol)。
每個(gè)object file中都會(huì)有一個(gè)相應(yīng)的符號(hào)表 (symbol table),這個(gè)表中記錄了目標(biāo)文件中用到的所有符號(hào)。
符號(hào)表中最重要的兩類符號(hào):
- 本目標(biāo)文件中的全局符號(hào),可以被其他目標(biāo)文件引用
- 本目標(biāo)文件中引用的全局符號(hào),卻沒(méi)有定義在本目標(biāo)文件中,這類是外部符號(hào),如printf
#include <iostream>
using namespace std;
int g_var1 = 100;
int g_var2;
void foo(int i)
{
cout << "i = " << i << endl;
}
int main()
{
static int s_var1 = 99;
static int s_var2;
int a = 1;
int b;
foo(g_var1 +s_var1 + a);
}
針對(duì)上面這個(gè)C++代碼,可以通過(guò)nm命令查看其符號(hào)表。

C++ 符號(hào)修飾
符號(hào)修飾(decorate)也稱為符號(hào)改編(mangle), compiler在將C++源碼編譯成object file時(shí),會(huì)將函數(shù)和變量的名字進(jìn)行修飾,形成符號(hào)名。

修飾方法:
- 所有的符號(hào)都以
_Z開(kāi)頭 - 對(duì)于嵌套的名字(在namespace或者class里),后面緊跟
N - 每個(gè)名字前面是名字長(zhǎng)度
- 以
E結(jié)尾 - 對(duì)于函數(shù),參數(shù)表緊跟在
E后面,對(duì)于int類型就是一個(gè)小寫(xiě)i
當(dāng)查看符號(hào)表的時(shí)候想查看裝飾前的名字的時(shí)候,推薦用如下命令:

extern "C": 將C++ code處理成C code


宏 __cplusplus
頭文件聲明了C語(yǔ)言的函數(shù)或變量,可以被C code或者C++ code引用。
如 C語(yǔ)言函數(shù)庫(kù)string.h中的
void* memset(void*, int, size_t);
- C code可以正確引用
memset - C++ code會(huì)修飾
memset, 這將導(dǎo)致linker無(wú)法與函數(shù)庫(kù)string.h中的memset符號(hào)進(jìn)行鏈接
C語(yǔ)言不支持extern "C"語(yǔ)法,如果為了兼容C語(yǔ)言和C++定義兩套頭文件,未免過(guò)于繁瑣。
解決問(wèn)題的方法是利用C++的宏 __cplusplus, C++編譯器會(huì)在編譯C++ code的時(shí)候默認(rèn)定義這個(gè)宏,可以使用條件宏來(lái)判斷當(dāng)前編譯單元是不是C++ code。

如果正在編譯C++ code,則
memset被extern "C"包裹,否則,就是直接聲明。上面這段代碼中的技巧在所有的系統(tǒng)頭文件里都被用到。
目標(biāo)文件
- 可執(zhí)行文件:
- Linux下位ELF (executable linkable format)
- Windows下PE (portable executable)
- 查看文件格式的命令:file
file filename

目標(biāo)文件的構(gòu)成

objdump: Display information form object file



可以用
size命令查看ELF文件的代碼段、數(shù)據(jù)段和bss段的長(zhǎng)度