1. 程式人生 > >C/C++ 程式編譯與連結的過程詳解(靜態連結)

C/C++ 程式編譯與連結的過程詳解(靜態連結)

我們知道一個程式的執行需要經過編譯和連結兩個階段,其過程究竟是怎樣的呢?

程式的編譯階段分為以下幾個步驟,分別是預編譯、編譯、彙編、生成二進位制可重定向檔案(.o)。

  1. 預編譯: 首先是原始碼檔案xxx.c和相關的標頭檔案被預編譯器編譯成一個.i檔案。對於C++程式來說,原始碼的副檔名可能是.cpp或.cxx,標頭檔案的副檔名是.hpp,而編譯後的副檔名是.ii。
    第一步的預編譯過程相當於如下指令:
    gcc -E hello.c -o hello.i 或 cpp hello.c > hello.i.
    預編譯過程做的事情:處理所有以#開頭的預編譯指令,刪除註釋,新增行號和檔名標識,保留所有的#pragma編譯器指令(因為編譯器要使用它們)。

  2. 編譯:進行語法分析、詞法分析和語義分析,並且將程式碼優化後產生相應的彙編程式碼檔案(ASCLL檔案),即.s 檔案。這個過程是整個程式構建的核心部分,也是最複雜的部分之一。
    相當於如下指令:
    gcc -S hello.i -o hello.s

  3. 彙編:通過不同平臺(Windows、Linux)的彙編器將彙編程式碼翻譯成機器碼,即生成二進位制可重定向檔案(.o)。
    相當於指令:
    as hello.s -o hello.o 或 gcc -c hello.s -o hello.o
    或者使用gcc命令將原始檔一部生成目標檔案:
    gcc -c hello.c -o hello.o
    何為二進位制可重定向檔案(.o)?為什麼是可重定向檔案?
    二進位制可重定向檔案包含二進位制程式碼和資料,其形式可以在連結時與其他二進位制可重定向檔案合併起來,由連結器產生一個可執行目標檔案。
    一個典型的二進位制可重定向檔案格式如下圖:

    二進位制可重定向檔案格式

    我自己編寫了兩個檔案:
    mian.c

#include <stdio.h>

int sum(int, int);

int main.c
{
    int a = 10;
    int b = 20;
    printf("sum=%d\n", sum(a, b));

    return 0;
}

a.c

int sum(int x, int y)
{
    return x + y;
}

用命令
gcc -c main.c a.c 生成.o檔案,並用命令objdump -t main.o去檢視生成的符號表,如下圖所示:

那為什麼是可重定向呢?
在編譯階段編譯器和彙編器會生成每個檔案的符號表,符號表中存放的是由程式產生的符號,比如函式名,變數名等,從上圖可以看出,編譯器沒有給符號分配正確的地址(圖中地址全為0000 0000),所以在程式碼段計算機指令無法找到相應的變數或函式的地址,因此,二進位制可重定向檔案是無法執行的。所以二進位制可重定向檔案得等到重定向以後才成為可執行檔案。

程式的連結階段可分為兩個步驟:
第一步:連結器首先將多個.o 檔案相應的段進行合併,建立對映關係並且去合併符號表。進行符號解析(符號解析的目的是讓所有符號的引用找到該符號的定義,如上圖中UND後面的符號),符號解析完成後就是給符號分配虛擬地址。

第二步:將分配好的虛擬地址與符號表中的定義的符號一一對應起來,使其成為正確的地址,是程式碼段的指令可以根據符號的地址執行相應的操作,最後由連結器生成可執行檔案。

相關推薦

C/C++ 程式編譯連結過程靜態連結

我們知道一個程式的執行需要經過編譯和連結兩個階段,其過程究竟是怎樣的呢? 程式的編譯階段分為以下幾個步驟,分別是預編譯、編譯、彙編、生成二進位制可重定向檔案(.o)。 預編譯: 首先是原始碼檔案xxx.c和相關的標頭檔案被預編譯器編譯成一個.i檔案。

c語言連結串列超詳細

連結串列是一種常見的基礎資料結構,結構體指標在這裡得到了充分的利用。連結串列可以動態的進行儲存分配,也就是說,連結串列是一個功能極為強大的陣列,他可以在節點中定義多種資料型別,還可以根據需要隨意增添,刪除,插入節點。連結串列都有一個頭指標,一般以head來表示,存放的是一個地

元資料資料治理|Apache Atlas安裝過程初步版本

                                  Apache Atlas安裝過程詳解 一 

Apache Hadoop1.1.1+Apache Oozie3.3.2搭建安裝過程親測

寫在前面: 最近需要定製的原因,需要將原來Cloudera版本的Hadoop更改為Apache版本的Hadoop和Oozie,對官方文件的學習,發現Hadoop1.1.1和Oozie3.3.2的組合比較好,所以,經過幾天的搭建,終於成功了,現在把心得分享出來,希望給需要的朋

C/C++編譯連結過程 (重定向表,匯出符號表,未解決符號表)

詳解link  有 些人寫C/C++(以下假定為C++)程式,對unresolved external link或者duplicated external simbol的錯誤資訊不知所措(因為這樣的錯誤資訊不能定位到某一行)。或者對語言的一些部分不知道為什麼要(或者不要)這樣那樣設計。瞭解本文之後, 或許會有

c/c++預處理過程之條件編譯及預定義的巨集

未經博主同意不得私自轉載!不準各種形式的貼上複製本文及盜圖! 首先對於上篇文章中巨集定義的補充: (1)#define NAME"zhangyuncong" 程式中有"NAME"則,它會不會被替換呢? (2)#define 0x abcd 可以嗎?也就是說,可不可以用不是

C++ 編譯,執行過程

        要更深入瞭解C++, 必須要知道一個程式從開始到結束都幹了些什麼, 怎麼幹的。 所以我從C++編譯到執行過程,解析下程式是怎麼跑的。         首先,初略的說一下之前C++的編譯過程,C++編譯過程包括預編譯-》彙編-》編譯-》連結。稱為一個可執行檔案

順序表的建立和初始化過程C語言實現

順序表存放資料的特點和陣列這種資料型別完全吻合,因此順序表的實現使用的是陣列。需要注意的是,使用陣列實現順序表時,一定要預先申請足夠大的記憶體空間,避免因儲存空間不足,造成資料溢位,導致不必要的程式錯誤甚至崩潰。 在建立順序表時,除了預先申請記憶體空間,還需要實時記錄順序表的長度和順序表本身申請的記憶體大

Shapley演算法解決舞伴問題過程C++實現

舞伴問題是這樣的:有 n 個男孩與 n 個女孩參加舞會,每個男孩和女孩均交給主持一個名單,寫上他(她)中意的舞伴名字。無論男孩還是女孩,提交給主持人的名單都是按照偏愛程度排序的,排在前面的都是他們最中意的舞伴。試問主持人在收到名單後,是否可以將他們分成 n 對,使每個人都能和他們中意的舞伴結對跳舞?為了避免舞

C語言面向物件程式設計:繼承2

在 C 語言面向物件程式設計(一)裡說到繼承,這裡再詳細說一下。     C++ 中的繼承,從派生類與基類的關係來看(出於對比 C 與 C++,只說公有繼承): 派生類內部可以直接使用基類的 public 、protected 成員(包括變數

js 程式執行順序實現

轉自:http://www.jb51.net/article/36755.htm 函式的宣告和呼叫 JavaScript是一種描述型指令碼語言,由瀏覽器進行動態的解析與執行。函式的定義方式大體有以下兩種,瀏覽器對於不同的方式有不同的解析順序。 程式碼如下: 複製程式碼 程式碼如下

AVL樹插入刪除演算法有圖 -- C++語言實現

一:AVL樹介紹 AVL樹本質上還是一棵二叉搜尋樹,它的特點是: 1.本身首先是一棵二叉搜尋樹。 2.帶有平衡條件:每個結點的左右子樹的高度之差的絕對值(平衡因子)最多為1。在本文中用分別用-1,0,1定義左邊樹高,等高,右邊樹高。平衡因子用m_bf表示。 也就是說,AV

解除安裝安裝Node.jsnpm過程

下面記錄一下在本地 Windwos 環境用 vagrant 搭建的虛擬機器(Homestaead)和生產環境阿里雲 CentOS 系統安裝 Node.js 的步驟,以及 npm 安裝依賴的不同之處。 使用原始碼編譯的方式安裝 node.js.首先將機子上的 Node.js

OGRE啟動過程OGRE HelloWorld程式原理解析

平:本文比較系統深入的講述了OGRE啟動的全過程。我感覺不適合OGRE入門使用。不過我寫的挺好的。     本文介紹 OGRE 3D 1.9 程式的啟動過程,即從程式啟動到3D圖形呈現,背後有哪些OGRE相關的程式碼被執行。會涉及的OGRE類包括: Root

C/C++高精度運算(大整數運算)含壓位

1.高精度加法1.1 高精度加法        高精度運算的基本運算就是加和減。和算數的加減規則一樣,模擬豎式計算,考慮錯位運算與進位處理。下面是我老師給的程式碼,目前比網上其他的程式碼要精簡和巧妙。#include <cstdio> #include <c

asp.net打包過程WEB程式也能打包

{  base.Install(stateSaver);  StreamWriter sw2=System.IO.File.CreateText(Context.Parameters["des"].ToString()+"WebSystem.url"); //Context.Parameters["des"]

深度學習-卷積神經網路CNN-BN(Batch Normalization) 原理使用過程

前言 Batch Normalization是由google提出的一種訓練優化方法。參考論文:Batch Normalization Accelerating Deep Network Training by Reducing Internal Covariate Shif

C++函式指標例項篇四

#include <iostream> using namespace std ; typedef const double* (*FUN[3])(const double *, int) ; const double* call_001(const do

GCC編譯系統基本過程

GCC編譯驅動程式,將源程式hello.c翻譯為一個可執行目標檔案hello過程,分為四個階段; 下面是我總結的思維導圖,比純文字的好理解一點。   第一階段,預處理階段;前處理器(cpp)根據以