2. 編譯的工作內容
3. 彙編的工作內容
4. 鏈結器的工作內容
參考
#include int main()
使用gcc編譯器:
gcc hello.c
./a.out
a.out 含義是 assembler output 即 彙編輸出
上述過程可以分解為四個步驟:
1. 預處理(prepressing) gcc -e hello.c 生成 xx.i檔案
2. 編譯(compilation) gcc -s xx.i 生成 xx.s
3. 彙編(assembly) gcc -c xx.s 生成 xx.o
5. 鏈結(linking) gcc xx.o 生成 a.out
gcc -e hello.c -o hello.i
預編譯過程主要處理那些原始檔中以「#」開始的預編譯指令
比如:#include #define #if #ifdef
編譯器就是將高階語言翻譯成機器語言的乙個工具。
1. 將所有的#define 刪除,並且展開所有的巨集定義
2. 處理所有條件編譯指令,如#if #ifdef #elif #else #endif
3. 處理#include預編譯指令,將包含的檔案插入到該預編譯指令的位置,這個過程是遞迴進行的。
4. 刪除所有的注釋 // 和 /**/
5. 新增行號和檔名標識,比如 #2 hello.c 2 ,以便除錯資訊,錯誤,告警等顯示行號
6. 保留所有的#pragma等編譯器指令,因為編譯器需要他們
結果:經過預編譯後的hello.i檔案不包含任何巨集定義,因為所有的巨集已經被展開。
gcc -s hello.i -o hello.s
編譯過程:編譯過程一般可以分為6步:掃瞄、詞法分析,語法分析,語義分析、源**優化、**生成、目標**優化。
1. 掃瞄:首先源**被輸入到掃瞄器(scanner)
2. 詞法分析:將源**的字串行分割成一系列的記號
記號分為: 關鍵字,識別符號,字面量(數字字串),特殊符號
3. 語法分析:對記號進行語法分析,產生語法樹(syntax tree),就是以表示式為節點的樹
4. 語義分析:給語法樹的表示式標識型別
5. 中間語言生成:簡單的**優化,如 4+5 直接計算結果
6. 目標**生成與優化:選擇合適的定址方式、使用位移來代替乘法運算、刪除多餘的指令等
後面將圖貼上來!
gcc -c hello.s -o hello.o
彙編:將彙編**轉變成機器可以執行的**指令,每乙個彙編語句幾乎都對應一條機器指令。
重定位(relocation):重新計算各個目標的位址過程叫做重定位(relocation)
符號(symbol):表示乙個位址,這個位址可以是一段子程式/函式,也可以是乙個變數的起始位址。
模組之間的呼叫歸結為如何通訊的問題,常見是模組間的函式呼叫和模組間的變數訪問。
模組的拼接的過程就是鏈結
鏈結(linking):主要內容就是把各個模組之間的相互引用的部分都處理好,使得各個模組之間能夠正確的銜接。
鏈結的主要過程:包括位址和空間分配,符號決議,重定位
庫:其實是一組目標檔案的包,就是一些最常用的**編譯成的目標檔案後打包存放。
執行時庫(running library):它是支援程式執行的基本函式的集合
詳細參考之前的部落格
C 預編譯 編譯 彙編 鏈結
windows中以2 2劃分核心 使用者空間,linux中以1 3劃分核心 使用者空間。在text段中,只有普通區域性變數是指令 int gdata1 10 data 已初始化且初始化不為零的資料 int gdata2 0 bss 未初始化或初始化為零的資料 int gdata3 bss stati...
編譯原理 預編譯 編譯 彙編與鏈結
我們編寫的程式 是怎樣執行起來的?到底執行的是什麼內容?平時我們所說的編譯主要包括預編譯 編譯 彙編與鏈結,這四部分分別都幹什麼工作,主要職能有哪些。講述編譯之前,我們先要了解程式記憶體。乙個由c c 編譯的程式占用的記憶體,大致分為以下幾個部分 1 棧區 stack 由編譯器自動分配釋放 存放函式...
預編譯 編譯 彙編 鏈結過程
將源 或者標頭檔案經過預編譯成乙個.i檔案。例如c 副檔名是.cpp,標頭檔案的副檔名可能是.hpp,預編譯後的副檔名是.i 預編譯的過程相當於下面的命令 對c語言檔案的處理 gcc e 原始檔 o目標檔案 對c 語言的檔案的處理 g gcc e 原始檔 o目標檔案 例如 gcc e hello.c...