編譯,鏈結 一

2021-08-31 11:40:30 字數 1948 閱讀 7238

.c/.cpp檔案 ->.exe檔案

需要經過   預編譯         編譯          彙編            鏈結

虛擬記憶體空間:

分為:約128m:0x08048000

.text 段:儲存**(指令)

.data段: 資料段(儲存所有的已初始化的全域性變數和所有區域性變數)

.bss段: 儲存未初始化的全域性變數(不占用空間,內容儲存在.comment段)

。。。其他字段(初始8個,還有可能有更多的)

間隔共享庫區:dll檔案等

間隔命令列引數:

環境變數

核心空間(不允許訪問:linux:1:3,windows:2:2)0xc000 0000

0xffff ffff

命令列引數:

main函式引數:

int main(int argc,char* argv,char env)

傳參舉例: ./a.out "hello"

int argc:引數個數

char* argv:字串陣列,給main函式傳入的字串陣列

char* env:傳入的環境變數,如「path=c:/dos

./c  或 .cpp:

經過      預編譯 ->.i 檔案 

1.把#define 替換

2.把#include展開

3.把#if #endif  #elseif 去除

4.刪除注釋

5.新增行號

6.保留#pragma(編譯)

編譯-> .s檔案 

1.詞法分析

2.語法分析

3.語義分析(是否有歧義)

4.**優化(簡化)

彙編-> .o檔案  彙編指令**翻譯成二進位制

鏈結-> .exe檔案

1.合併段和符號表

2.符號解析

3.分配位址和空間(原來沒有位址的分配位址)

4.符號的重定位(強弱符號的選取)

linux:elf格式檔案

window :pe格式檔案

每個.c/.cpp檔案:

elf header 

.text

.data

(為了和實位址相對應)

強弱符號:

強符號:已初始化的全域性變數

弱符號:未初始化的全域性變數

強弱符號的規則

1.兩強:重定義(報錯)

2.一強一弱:選強

3.兩弱:(看編譯器:任選乙個或者報錯)

int gdata1 = 10;//.data    已初始化 且 初始化不為零的資料

int gdata2 = 10;//.bss   未初始化 或 初始化不為零的資料

int gdata3;        //.bss

static int gdata4 = 20;  //.data

static int gdata5 = 0;    //.bss

static int gdata6;           //.bss

int main()

c語言下:

main.c

#includeshort a = 10;

short b = 20;

extern fun();

int main()

test.c:

如果沒有邊界控制:

int a;

void fun()

結果會列印a = 30和b = 0;

在符號重定位的時候會判斷強弱符號,結果合併為short型別的符號,但在鏈結之前的test.c編譯過程中,編譯器認為a為int型別,賦給a的位址乙個4位元組的30;在鏈結後,仍然賦給a 4位元組的30,但接受時的a已經為兩位元組的資料了,所以賦值越位了,把下面的2位元組b的值給覆蓋成0。

靜態鏈結 編譯和鏈結(一)

彙編鏈結 小結本文主要是 程式設計師的自我修養 一書的內容摘要和梳理,如有需要並且沒有被本文涵蓋的內容,建議讀者自行 原書。靜態鏈結 目標檔案 二 靜態鏈結 靜態鏈結 三 裝載與動態鏈結 裝載與程序 一 裝載與動態鏈結 動態鏈結 二 本部分主要是介紹關於程式源 是如何到可執行檔案的,及這其中涉及到的...

編譯和鏈結 一

先從乙個最簡單的案例入手 helloworld.c,這裡我就不寫了,大家都寫過,我把它編譯成可執行程式gcc o helloworld helloworld.c 預處理 將所有的巨集定義替換 include檔案展開 刪除所有的注釋 新增行號和檔名標示 當然還有保留 pragma編譯指令等 編譯 把檔...

編譯鏈結過程(一)

什麼是編譯?什麼是鏈結?為什麼需要編譯和鏈結?在很久以前,計算機發展的初期,還在用機器語言編寫程式,量比較少時是不需要編譯和鏈結的。因為當時的程式設計師直接編寫機器碼讓計算機執行。每種cpu的指令是不相同的,所以每乙個程式要換一台不同cpu的機器上執行時,需要重新寫程式,而且機器語言 涉及很多計算機...