編譯和連接

If you change a single file, you will have to recreate the object code file from
模塊間的拼合就是鏈接linking

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)表。

nm object文件名

C++ 符號(hào)修飾

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

gcc編譯器的symbol decoration

修飾方法

  • 所有的符號(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í)候,推薦用如下命令:


demangle

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

extern "C"用法舉例

可以看到extern "C"包裹的變量就沒(méi)有經(jīng)過(guò)修飾了

宏 __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。

使用條件宏來(lái)判斷當(dāng)前編譯單元是不是C++ code

如果正在編譯C++ code,則memsetextern "C"包裹,否則,就是直接聲明。上面這段代碼中的技巧在所有的系統(tǒng)頭文件里都被用到。

目標(biāo)文件

  • 可執(zhí)行文件:
  1. Linux下位ELF (executable linkable format)
  2. Windows下PE (portable executable)
  • 查看文件格式的命令:file
file filename
查看可執(zhí)行文件

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

C code and object file

objdump: Display information form object file

use objdump to display info from object

size和offset

object file在ELF中的結(jié)構(gòu)

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

readelf: Display information about ELF files

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容