編譯 連結 執行原理
一、
在80386之前是真實模式,80386之後是保護模式
所謂的32位、62位是指 ALU的寬度,即一次效能處理最大資料長度(位元為單位)
在Windows作業系統下4G虛擬記憶體空間是,使用者空間:核心空間是1:1
在Linux作業系統下4G虛擬記憶體空間是,使用者空間:核心空間是3:1
Linux4G記憶體分配大致如下圖
圖1
.data 已初始化且初始化不為0的資料
.bss 未初始化或初始化為0的資料
區域性變數的普通變數是指令(.text)
二、
編譯
預編譯
生成.i檔案 命令:gcc -E main.c -o main.o
1.刪除#define
2.遞迴展開#include檔案
3.刪除#if0 #endif #elif
4.刪除註釋(// /**/)
5.新增行,檔案表示
6.保留#pragma
編譯
生成.s檔案 命令:gcc -S main.i -o main.s
1.詞法分析
2.語法分析
3.語義分析
4.程式碼優化
彙編
可重定位,可重入
生成.o檔案或.obj檔案 gcc -c main.s -o main.o
指令程式碼翻譯成二進位制
連結
生成.exe檔案
1.合併段和符號表
2.符號解析(在符號引用的地方找到符號定義的地方(只關注全域性符號))
3.分配地址和空間
4.符號重定位
三、目標檔案的分析
可執行檔案格式,Windows下問PE格式,Linux下為ELF格式,它們都是COFF格式的變種。目標檔案就是原始碼編譯後但未進行連線的那些中間檔案,它跟可執行檔案的內容結構很相似,所以一般跟可執行檔案格式一起採用一種格式儲存。
在此,使用main.c進行分析
編譯
輸入gcc -c *.c 命令對main.c檔案進行編譯生成main.o檔案
檢視目標檔案的結構和內容:objdump -h main.o
由此可畫出ELF檔案的大致結構
我們可以發現在.bss檔案中大小為20,但我們的main.c 程式中有6個int 型的資料在.bss段中存放,缺失了一個……
這時我們檢視符號表
發現!!!缺失的那個資料 gdata3在*COM*塊中
這是因為,
在c中,有強弱符號之分
強符號:已初始化的全域性變數
弱符號:未初始化的全域性變數
規則:
1.兩強(兩個同名強):重定義
2.一強一弱:選強符號
3.兩弱:選位元組較大的
此時函式的入口地址為0x0000 0000
連結
輸入命令ld -e main -o run main.o
此時有了入口地址
gdata3此時歸屬於.bss段了
ps:
修改main.c 新增sum.c
此時gdata、sum處於*UND*塊
通過連結
四、執行原理
1.建立虛擬地址空間和實體記憶體的對映(對映結構體)
2.載入指令資料
檢視program header 段
3.第一行指令的地址寫入pc暫存器中