【C語言編譯】編譯原理和詳細過程

文章目錄

  • 1. C 語言編譯原理和詳細過程
    • 1.1 預處理階段
    • 1.2 編譯階段
    • 1.3 匯編階段
    • 1.4 鏈接階段
  • 2. 疑問點解析
    • 2.1 三地址碼是什么?有什么作用
    • 2.2 符號表是什么?有何作用
    • 2.3 重定位的含義與作用
    • 2.3 符號表和重定位在整個編譯過程中的作用
    • 2.4 動態鏈接庫.so和靜態鏈接庫.a
    • 2.5 不要混淆.o文件和.so文件
  • 3. 知識補充

1. C 語言編譯原理和詳細過程

編譯是將源代碼轉換為計算機可執行的二進制文件的過程,整個過程主要分為四個階段: 預處理; 編譯; 匯編; 鏈接

1.1 預處理階段

工具:預處理器
輸入:.c 源文件
輸出:.i 預處理后的文件

預處理階段做的主要工作:

  • 宏展開:將所有#define定義的宏進行文本替換
  • 頭文件包含:遞歸展開#include指令,將頭文件內容插入源代碼
  • 條件編譯:處理條件編譯指令(如#ifdef等命令),根據條件保留或刪除代碼塊(如調試代碼)
  • 刪除注釋

1.2 編譯階段

工具:編譯器
輸入:.i文件
輸出:.s匯編代碼文件

編譯階段做的主要工作:

  • 詞法分析:將代碼拆分為token(如標識符,關鍵字,運算符)
  • 語法分析:構建抽象語法樹(AST),檢查語法是否符合C標準(如檢查括號是否匹配,語句是否合法)
  • 語義分析:檢查類型匹配,變量聲明,作用域規則
  • 中間代碼生成:生成與平臺無關的中間表示(如三地址碼)
  • 代碼優化:對中間代碼進行優化。如刪除冗余代碼、常量折疊等
  • 目標代碼生成:將優化后的中間代碼轉換為目標平臺的匯編代碼

1.3 匯編階段

工具:匯編器
輸入:.s匯編文件
輸出:.o目標文件,即二進制機器碼
匯編階段做的主要工作:

  • 指令轉換:將匯編代碼逐行轉換為機器碼
  • 生成目標文件:生成包含機器碼、符號表、重定位信息的**.o文件**

1.4 鏈接階段

工具:鏈接器
輸入:多個.o目標文件+靜態庫.a文件
輸出:可執行文件
鏈接階段做的主要工作:

  • 符號解析:解決跨文件的函數或變量引用。如main.o中調用printf函數,則需找到該函數在libc.a中的定義
  • 重定位:合并所有目標文件的代碼段、數據段,分配最終內存地址;修正符號表中的地址偏移量
  • 庫文件處理
      - 靜態鏈接:將靜態庫.a代碼直接復制到可執行文件中
      - 動態鏈接:記錄動態庫.so的路徑,運行時加載
  • 生成可執行文件:生成符合操作系統格式的可執行文件

注:可執行文件分為 代碼段(.text)、數據段(.data)、未初始化數據段(.bss)

經過這一系列過程,c源代碼最終變成了操作系統可直接執行的二進制文件 運行時由加載器將其讀入內存并執行。

2. 疑問點解析

2.1 三地址碼是什么?有什么作用

三地址碼(Three-Address Code,TAC)是編譯器中常用的一種中間表示(Intermediate Representation, IR)形式,它將復雜的表達式和語句拆解為一系列簡單的指令,每條指令最多包含三個操作數。它的核心目標是簡化代碼優化和目標代碼生成的過程,同時保持與機器無關的特性。
每條指令僅包含一個操作(如賦值,運算,跳轉等),最多涉及三個操作數,兩個輸入一個輸出。常見的通用格式如下:

result = operand1 op operand2

2.2 符號表是什么?有何作用

符號表是編譯器/匯編器生成的一種數據結構,記錄了程序中所有符號的信息:

  • 符號名稱:如函數名、全局變量名稱;
  • 符號類型:函數、變量、靜態/全局作用域等;
  • 符號地址:在目標文件中的相對地址或內存地址。

符號分類:

  • 全局符號:可被其他文件訪問的符號,如extern變量、非static函數;
  • 局部符號:僅在本文件內可見的符號,如static函數或變量;
  • 外部符號:在本文件中使用但未定義的符號,如調用了其他文件中的函數。

在鏈接階段,鏈接器通過符號表解析不同目標文件之間的符號引用,如函數調用、變量訪問等;符號表包含了符號的地址和類型,支持調試器(如gdb)定位代碼和變量(比如有時候調試的時候會導入符號表);動態鏈接庫.so需要依賴符號表在運行時綁定函數地址。

2.3 重定位的含義與作用

重定位時鏈接器在合并多個目標文件時,修正符號引用地址的過程。目標文件.o中的代碼和數據地址是臨時地址(基于偏移量的),鏈接器需要將其調整為最終可執行文件的絕對地址。

重定位表:每個目標文件都有一個重定位表,記錄了需要修正的位置及其規則:

  • 需要修正的偏移量:在目標文件中的位置;
  • 符號名稱:需要修正為哪個符號的地址;
  • 重定位類型:如何計算最終地址,如相對地址或絕對地址。

重定位的作用:

  • 合并多目標文件:將分散在多個.o文件中的代碼和數據分配到統一的內存布局中;
  • 解析外部依賴:將未定義的符號綁定到庫中的實際地址;
  • 生成可執行文件:確保程序運行時,所有指令和數據的地址正確。

2.3 符號表和重定位在整個編譯過程中的作用

編譯階段會生成符號表并記錄重定位信息:

  • 生成符號表:編譯器為每個.c文件生成.o目標文件,包含符號表和代碼;
  • 記錄重定位信息:編譯器標記所有需要重定位的位置,如外部函數調用等。

鏈接階段會進行符號解析以及地址分配與重定位:

  • 符號解析:鏈接器會檢查所有目標文件的符號表,確保每個符號有且僅有一個定義;
  • 地址分配與重定位:鏈接器為所有符號分配最終地址,并修正代碼中的引用。

即符號表是程序符號的地址簿,記錄了符號的定義和引用;重定位是鏈接器的修正工具,確保程序可以正確訪問所有符號。

2.4 動態鏈接庫.so和靜態鏈接庫.a

動態鏈接庫.so文件,是在程序運行時被加載的,多個程序可共享同一個庫文件,節省內存和磁盤空間。

靜態鏈接庫.a文件,是在編譯時整合到可執行文件中,生成獨立的可執行文件,不需要外部依賴。

靜態鏈接庫和動態鏈接庫的主要區別:

特性靜態庫(.a)動態庫(.so)
鏈接方式編譯時直接嵌入到可執行文件中程序運行時動態加載
文件體積可執行文件體積較大(包含庫代碼)可執行文件體積較小(僅存引用)
運行時依賴無需外部庫文件必須存在對應的.so文件
內存占用每個進程獨立加載庫代碼,內存冗余多個進程共享同一份庫代碼,內存節省
更新維護需重新編譯整個程序僅替換.so文件即可更新庫功能
加載速度啟動快(代碼已嵌入)啟動稍慢(需加載動態庫)
兼容性風險無版本沖突問題需保證.so版本與程序兼容
常見使用場景嵌入式系統、獨立工具、無依賴部署通用系統庫(如libc)、多進程共享場景

示例:

  1. 靜態鏈接:

    gcc main.c -o program -L/path/to/libs -lstaticlib -static
    

    -static選項表明強制靜態鏈接所有庫,包括庫系統如libc
    這樣生成的program不依賴任何外部庫。

  2. 動態鏈接:

    gcc main.c -o program -L/path/to/libs -ldynamiclib
    

    默認鏈接動態庫(優先查找.so),運行時需確保動態庫在系統路徑或通過LD_LIBRARY_PATH指定。

  3. 混合鏈接:

    gcc main.c -o program -Wl,-Bstatic -lstaticlib -Wl,-Bdynamic -ldynamiclib
    
    • -Wl,-Bstatic:指定后續庫靜態鏈接。
    • -Wl,-Bdynamic:恢復為動態鏈接

2.5 不要混淆.o文件和.so文件

.o文件是目標文件,通常是編譯單個源文件后的輸出,包含機器碼和符號表,但還未經過鏈接,所以可能有未解析的符號

.so文件是動態鏈接庫,是多個目標文件經過鏈接后生成的共享庫,可以在運行時被多個程序共享。

.o文件是編譯階段的產物,.so文件是鏈接階段的產物;.so文件在程序運行時加載,.o文件在鏈接時被合并到可執行文件或靜態庫中。

二者主要區別:

特性目標文件(.o)動態鏈接庫(.so)
生成階段編譯階段的產物(單個源文件編譯后生成)鏈接階段的產物(多個目標文件或源碼鏈接生成)
內容包含單個源文件編譯后的機器碼、符號表、重定位信息包含多個目標文件或源碼的已鏈接代碼,具有完整的符號解析和地址分配
用途作為中間文件,供后續鏈接生成可執行文件或庫作為共享庫,供程序在運行時動態加載
依賴關系未解析的符號需在鏈接階段解決符號已完全解析,但需在運行時與主程序或其他庫動態綁定
文件獨立性無法單獨運行,需鏈接后使用可獨立存在,但需主程序調用或動態加載
內存共享不共享,每個進程獨立加載多個進程可共享同一份.so的代碼段,節省內存
更新維護修改后需重新編譯和鏈接更新.so后,主程序無需重新編譯(需接口兼容)

.o文件,通過編譯單個源文件生成,包含機器碼、符號表和重定位信息。.o文件作為中間文件,以供后續鏈接器將所有.o文件合并為可執行文件或庫(可被歸檔為靜態庫.a文件,本質上是多個.o的集合)

.so文件,通過鏈接多個目標文件或源碼生成,包含完全鏈接的代碼(所有的符號已解析,除非依賴其他動態庫)、位置無關代碼(代碼可加載到任意內存地址運行)、導出符號表(聲明庫中可供外部調用的函數或變量)。.so文件是在程序運行時由動態鏈接器加載到內存的,多個程序可共享一份.so代碼,減少內存占用,同時支持庫的熱更新(即替換.so文件后重啟程序生效)

總結:

  • .o文件是編譯階段的中間產物,用于后續鏈接;.so文件鏈接后的動態庫,用于運行時共享。
  • .o文件聚焦單個模塊的編譯結果,.so文件聚焦多模塊的協作與動態加載。

3. 知識補充

【GCC】gcc編譯學習
【GDB】gdb使用

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/78578.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/78578.shtml
英文地址,請注明出處:http://en.pswp.cn/web/78578.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

游戲引擎學習第251天:完成調試層級結構

運行游戲,查看當前調試層級的狀態。 我們正在直播中開發一個完整的游戲,目前正進行調試代碼的整理和清理工作。現在我們直接進入正題,雖然還不完全確定今天要完成哪些具體內容,但有幾個明確的目標: 首先,…

關于Python:9. 深入理解Python運行機制

一、Python內存管理(引用計數、垃圾回收) Python(CPython)采用的是: “引用計數為主,垃圾回收為輔” 的內存管理機制。 也就是說: 引用計數機制:負責大部分內存釋放,簡…

【STM32單片機】#13 RTC實時時鐘

主要參考學習資料: B站江協科技 STM32入門教程-2023版 細致講解 中文字幕 開發資料下載鏈接:https://pan.baidu.com/s/1h_UjuQKDX9IpP-U1Effbsw?pwddspb 單片機套裝:STM32F103C8T6開發板單片機C6T6核心板 實驗板最小系統板套件科協 目錄 Uni…

SecureCRT 使用指南:安裝、設置與高效操作

目錄 一、SecureCRT 簡介 1.1 什么是 SecureCRT? 1.2 核心功能亮點 1.3 軟件特點 二、SecureCRT 安裝與激活 2.1 安裝步驟(Windows 系統) 2.2 激活與破解(僅供學習參考) 三、基礎配置與優化 3.1 界面與編碼設…

3.5/Q1,GBD數據庫最新一區文章解讀

文章題目:Global burden of low vision and blindness due to age-related macular degeneration from 1990 to 2021 and projections for 2050 DOI:10.1186/s12889-024-21047-x 中文標題:1990年至2021年因年齡相關性黃斑變性導致的低視力和失…

【Hive入門】Hive安全管理與權限控制:基于SQL標準的授權GRANT REVOKE深度解析

目錄 引言 1 Hive權限模型概述 2 SQL標準授權基礎 2.1 核心概念解析 2.2 授權模型工作流程 3 GRANT/REVOKE語法詳解 3.1 基礎授權語法 3.2 權限回收語法 3.3 參數說明 4 授權場景 4.1 基礎授權示例 4.2 列級權限控制 4.3 視圖權限管理 5 權限查詢與驗證 5.1 查看…

無縫監控:利用 AWS X-Ray 增強 S3 跨賬戶復制的可見性

您準備好提升您的云和 DevOps 技能了嗎? ??《云原生devops》專門為您打造,我們精心打造的 30 篇文章庫,這些文章涵蓋了 Azure、AWS 和 DevOps 方法論的眾多重要主題。無論您是希望精進專業知識的資深專業人士,還是渴望學習相關知識的新手,這套資源庫都能滿足您的需求。 …

Python Cookbook-7.2 使用 pickle 和 cPickle 模塊序列化數據

任務 你想以某種可以接受的速度序列化和重建Python 數據結構,這些數據既包括基本Python 對象也包括類和實例。 解決方案 如果你不想假設你的數據完全由基本 Python 對象組成,或者需要在不同的 Python 版本之間移植,再或者需要將序列化后的…

2025.5.5總結

今日感悟:這假期就這樣結束了,玩了一次滑板,打掃了一次租房,出去逛了一次街,看完了一本書,追了一部劇。既沒有家人,也沒有能一同暢飲的同學,更沒有對象,顯得確實有些孤獨…

MySQL | DQL語句-連接查詢

MySQL | DQL語句-連接查詢 🪄個人博客:https://vite.xingji.fun 什么是連接查詢 從一張表中查詢數據稱為單表查詢。從兩張或更多張表中聯合查詢數據稱為多表查詢,又叫做連接查詢。什么時候需要使用連接查詢? 比如這樣的需求&…

Vite簡單介紹

Vite 是一個現代化的前端構建工具,由 Vue.js 的創始人 Evan You 開發,旨在提供更快的開發體驗和更高效的構建流程。它的名字來源于法語單詞“vite”,意為“快速”,這也反映了它的核心優勢——極速的冷啟動和熱模塊替換&#xff08…

C語言-回調函數

回調函數 通過函數指針調用函數,而這個被調用的函數稱為回調函數 回調函數是C語言中一種強大的機制,允許將函數作為參數傳遞給其他函數,從而在特定時機由后者調用。它的核心在于函數指針的使用 以下是回調函數的使用例子 先創建好一個函數…

啟發式算法-禁忌搜索算法

禁忌搜索是一種可以用于解決組合優化問題的啟發式算法,通過引入記憶機制跳出局部最優,避免重復搜索。該算法從一個初始解開始,通過鄰域搜索策略來尋找當前解的鄰域解,并在鄰域解中選擇一個最優解作為下一次迭代的當前解&#xff0…

Python 整理3種查看神經網絡結構的方法

1. 網絡結構代碼 import torch import torch.nn as nn# 定義Actor-Critic模型 class ActorCritic(nn.Module):def __init__(self, state_dim, action_dim):super(ActorCritic, self).__init__()self.actor nn.Sequential(# 全連接層,輸入維度為 state_dim&#xf…

Linux 查詢CPU飆高的原因

獲取進程ID ps -efgrep xxxx查詢占用最高的線程ID top -Hp 線程ID線程ID 轉 16進制數 printf 0x%x\n 線程ID基于jstack工具 跟蹤堆棧定位代碼位置 jstack 進程ID | grep 16禁止線程ID -A 20

Oracle OCP認證考試考點詳解083系列09

題記: 本系列主要講解Oracle OCP認證考試考點(題目),適用于19C/21C,跟著學OCP考試必過。 41. 第41題: 題目 解析及答案: 關于應用程序容器,以下哪三項是正確的? A) 它可以包含單個…

GESP2024年3月認證C++八級( 第二部分判斷題(1-5))

孫子定理參考程序&#xff1a; #include <iostream> #include <vector> using namespace std;// 擴展歐幾里得算法&#xff1a;用于求逆元 int extendedGCD(int a, int b, int &x, int &y) {if (b 0) {x 1; y 0;return a;}int x1, y1;int gcd extende…

C 語言比較運算符:程序如何做出“判斷”?

各類資料學習下載合集 ??https://pan.quark.cn/s/8c91ccb5a474?? 在編寫程序時,我們經常需要根據不同的條件來執行不同的代碼。比如,如果一個分數大于 60 分,就判斷為及格;如果用戶的年齡小于 18 歲,就禁止訪問某個內容等等。這些“判斷”的核心,就依賴于程序能夠比…

WITH在MYSQL中的用法

WITH 子句&#xff08;也稱為公共表表達式&#xff0c;Common Table Expression&#xff0c;簡稱 CTE&#xff09;是 SQL 中一種強大的查詢構建工具&#xff0c;它可以顯著提高復雜查詢的可讀性和可維護性。 一、基本語法結構 WITH cte_name AS (SELECT ... -- 定義CTE的查詢…

多序列比對軟件MAFFT介紹

MAFFT(Multiple Alignment using Fast Fourier Transform)是一款廣泛使用且高效的多序列比對軟件,由日本京都大學的Katoh Kazutaka等人開發,最早發布于2002年,并持續迭代優化至今。 它支持從幾十條到上萬條核酸或蛋白質序列的快速比對,同時在準確率和計算效率之間提供靈…