可執(zhí)行文件

一個(gè)可執(zhí)行文件的生成一般都要經(jīng)過(guò)下面幾個(gè)步驟:
編輯 仲锄、預(yù)處理 扔嵌、 編譯、優(yōu)化本昏、匯編 供汛、 連接 ——>可執(zhí)行文件
下面將從這幾個(gè)步驟一個(gè)一個(gè)來(lái)分析他們的具體內(nèi)容。

  1. 編輯
    編輯這個(gè)過(guò)程其實(shí)挺簡(jiǎn)單的,但也是最講究的怔昨,它直接體現(xiàn)了一個(gè)編程者的編程習(xí)慣雀久,以及影響到別人對(duì)程序的閱讀感受,所以有必要總結(jié)一下趁舀。
    (1) 注釋要規(guī)范岸啡,多用 /...../ ,少用// ,邏輯復(fù)雜的函數(shù)要注明函數(shù)的功能以及每個(gè)參數(shù)的含義赫编,全局變量以及結(jié)構(gòu)體要注明用處
    (2) 一定要注意縮進(jìn)巡蘸,tab設(shè)置為4個(gè)空格會(huì)看起來(lái)更緊湊
    (3) 分支語(yǔ)句對(duì)應(yīng)的兩個(gè)大括號(hào)要獨(dú)占一行,而且盡量靠近行的開(kāi)頭
    (4) 注意程序的結(jié)構(gòu)性和層次性
    (5) 大型程序應(yīng)該對(duì)函數(shù)的功能以及模塊進(jìn)行歸類
    (6) 使用一個(gè)好的擂送,適合自己的編輯器

  2. 預(yù)處理
    預(yù)處理其實(shí)就是對(duì)所有源代碼進(jìn)行整合的一個(gè)過(guò)程悦荒,它將該程序所涉及到的所有代碼,包括頭文件嘹吨、宏定義搬味、條件編譯和執(zhí)行代碼,都整合為一個(gè)整體蟀拷。
    預(yù)處理過(guò)程會(huì)完成以下工作:
    (1) 文件包含:包括兩種格式 #include <my.h> #include "my.h"
    第一種方法是用尖括號(hào)把頭文件括起來(lái)碰纬,這種格式告訴預(yù)處理程序在編譯器自帶的或外部庫(kù)的頭文件中搜索被包含的頭文件。第二種方法是用雙引號(hào)把頭文件括起來(lái)问芬,這種格式告訴預(yù)處理程序在當(dāng)前被編譯的應(yīng)用程序的源代碼文件中搜索被包含的頭文件悦析,如果找不到,再搜索編譯器自帶的頭文件此衅。在預(yù)處理時(shí)强戴,會(huì)將對(duì)應(yīng)文件的全部?jī)?nèi)容插入并替換該#include語(yǔ)句, 如果這個(gè)頭文件還包含另外一個(gè)頭文件挡鞍,那么另外一個(gè)頭文件也會(huì)先替換調(diào)用它的的#include語(yǔ)句
    (2) 宏替換:將函數(shù)中使用到宏的地方骑歹,都使用對(duì)應(yīng)的值進(jìn)行替換,這些值主要是#define 命令聲明的
    (3) 條件編譯:將不符合條件編譯的語(yǔ)句刪除墨微,保留符合條件編譯的語(yǔ)句道媚。比如#if 0 ... #endif \ #if defined.... #endif 等條件編譯語(yǔ)句,不符合對(duì)應(yīng)條件的語(yǔ)句將會(huì)被丟掉翘县,而保留符合條件編譯的部分
    (4) 特殊符號(hào):預(yù)編譯程序可以識(shí)別一些特殊的符號(hào)最域,例如在源程序中出現(xiàn)的LINE標(biāo)識(shí)將被解釋為當(dāng)前行號(hào)(十進(jìn)制數(shù)),F(xiàn)ILE則被解釋為當(dāng)前被編譯的C源程序的名稱炼蹦。預(yù)編譯程序?qū)τ谠谠闯绦蛑谐霈F(xiàn)的這些串將用合適的值進(jìn)行替換羡宙。
    (5) 整理:刪除程序中的注釋和多余的空白字符

3.優(yōu)化階段

優(yōu)化處理是編譯系統(tǒng)中一項(xiàng)比較艱深的技術(shù)。它涉及到的問(wèn)題不僅同編譯技術(shù)本身有關(guān)掐隐,而且同機(jī)器的硬件環(huán)境也有很大的關(guān)系狗热。優(yōu)化一部分是對(duì)中間代碼的優(yōu)化钞馁。這種優(yōu)化不依賴于具體的計(jì)算機(jī)。另一種優(yōu)化則主要針對(duì)目標(biāo)代碼的生成而進(jìn)行的匿刮。上圖中僧凰,我們將優(yōu)化階段放在編譯程序的后面,這是一種比較籠統(tǒng)的表示熟丸。

對(duì)于前一種優(yōu)化训措,主要的工作是刪除公共表達(dá)式、循環(huán)優(yōu)化(代碼外提光羞、強(qiáng)度削弱绩鸣、變換循環(huán)控制條件、已知量的合并等)纱兑、復(fù)寫傳播呀闻,以及無(wú)用賦值的刪除,等等潜慎。后一種類型的優(yōu)化同機(jī)器的硬件結(jié)構(gòu)密切相關(guān)捡多,最主要的是考慮是如何充分利用機(jī)器的各個(gè)硬件寄存器存放的有關(guān)變量的值,以減少對(duì)于內(nèi)存的訪問(wèn)次數(shù)铐炫。另外垒手,如何根據(jù)機(jī)器硬件執(zhí)行指令的特點(diǎn)(如流水線、RISC倒信、CISC科贬、VLIW等)而對(duì)指令進(jìn)行一些調(diào)整使目標(biāo)代碼比較短,執(zhí)行的效率比較高堤结,也是一個(gè)重要的研究課題唆迁。

經(jīng)過(guò)優(yōu)化得到的匯編代碼必須經(jīng)過(guò)匯編程序的匯編轉(zhuǎn)換成相應(yīng)的機(jī)器指令鸭丛,方可能被機(jī)器執(zhí)行竞穷。

4.匯編過(guò)程

匯編過(guò)程實(shí)際上指把匯編語(yǔ)言代碼翻譯成目標(biāo)機(jī)器指令的過(guò)程。對(duì)于被翻譯系統(tǒng)處理的每一個(gè)C語(yǔ)言源程序鳞溉,都將最終經(jīng)過(guò)這一處理而得到相應(yīng)的目標(biāo)文件瘾带。目標(biāo)文件中所存放的也就是與源程序等效的目標(biāo)的機(jī)器語(yǔ)言代碼。 目標(biāo)文件由段組成熟菲。通常一個(gè)目標(biāo)文件中至少有兩個(gè)段:代碼段 該段中所包含的主要是程序的指令看政。該段一般是可讀和可執(zhí)行的,但一般卻不可寫抄罕。 數(shù)據(jù)段 主要存放程序中要用到的各種全局變量或靜態(tài)的數(shù)據(jù)允蚣。一般數(shù)據(jù)段都是可讀,可寫呆贿,可執(zhí)行的嚷兔。

UNIX環(huán)境下主要有三種類型的目標(biāo)文件:
(1)可重定位文件 其中包含有適合于其它目標(biāo)文件鏈接來(lái)創(chuàng)建一個(gè)可執(zhí)行的或者共享的目標(biāo)文件的代碼和數(shù)據(jù)森渐。
(2)共享的目標(biāo)文件 這種文件存放了適合于在兩種上下文里鏈接的代碼和數(shù)據(jù)。第一種事鏈接程序可把它與其它可重定位文件及共享的目標(biāo)文件一起處理來(lái)創(chuàng)建另一個(gè)目標(biāo)文件冒晰;第二種是動(dòng)態(tài)鏈接程序?qū)⑺c另一個(gè)可執(zhí)行文件及其它的共享目標(biāo)文件結(jié)合到一起同衣,創(chuàng)建一個(gè)進(jìn)程映象。
(3)可執(zhí)行文件 它包含了一個(gè)可以被操作系統(tǒng)創(chuàng)建一個(gè)進(jìn)程來(lái)執(zhí)行之的文件壶运。匯編程序生成的實(shí)際上是第一種類型的目標(biāo)文件耐齐。對(duì)于后兩種還需要其他的一些處理方能得到,這個(gè)就是鏈接程序的工作了蒋情。

5.鏈接程序

由匯編程序生成的目標(biāo)文件并不能立即就被執(zhí)行埠况,其中可能還有許多沒(méi)有解決的問(wèn)題。例如棵癣,某個(gè)源文件中的函數(shù)可能引用了另一個(gè)源文件中定義的某個(gè)符號(hào)(如變量或者函數(shù)調(diào)用等)询枚;在程序中可能調(diào)用了某個(gè)庫(kù)文件中的函數(shù),等等浙巫。所有的這些問(wèn)題金蜀,都需要經(jīng)鏈接程序的處理方能得以解決。

鏈接程序的主要工作就是將有關(guān)的目標(biāo)文件彼此相連接的畴,也即將在一個(gè)文件中引用的符號(hào)同該符號(hào)在另外一個(gè)文件中的定義連接起來(lái)渊抄,使得所有的這些目標(biāo)文件成為一個(gè)能夠被操作系統(tǒng)裝入執(zhí)行的統(tǒng)一整體。

根據(jù)開(kāi)發(fā)人員指定的同庫(kù)函數(shù)的鏈接方式的不同丧裁,鏈接處理可分為兩種:
(1)靜態(tài)鏈接 在這種鏈接方式下护桦,函數(shù)的代碼將從其所在地靜態(tài)鏈接庫(kù)中被拷貝到最終的可執(zhí)行程序中。這樣該程序在被執(zhí)行時(shí)這些代碼將被裝入到該進(jìn)程的虛擬地址空間中煎娇。靜態(tài)鏈接庫(kù)實(shí)際上是一個(gè)目標(biāo)文件的集合二庵,其中的每個(gè)文件含有庫(kù)中的一個(gè)或者一組相關(guān)函數(shù)的代碼。
(2)動(dòng)態(tài)鏈接 在此種方式下缓呛,函數(shù)的代碼被放到稱作是動(dòng)態(tài)鏈接庫(kù)或共享對(duì)象的某個(gè)目標(biāo)文件中催享。鏈接程序此時(shí)所作的只是在最終的可執(zhí)行程序中記錄下共享對(duì)象的名字以及其它少量的登記信息。在此可執(zhí)行文件被執(zhí)行時(shí)哟绊,動(dòng)態(tài)鏈接庫(kù)的全部?jī)?nèi)容將被映射到運(yùn)行時(shí)相應(yīng)進(jìn)程的虛地址空間因妙。動(dòng)態(tài)鏈接程序?qū)⒏鶕?jù)可執(zhí)行程序中記錄的信息找到相應(yīng)的函數(shù)代碼。

對(duì)于可執(zhí)行文件中的函數(shù)調(diào)用票髓,可分別采用動(dòng)態(tài)鏈接或靜態(tài)鏈接的方法攀涵。使用動(dòng)態(tài)鏈接能夠使最終的可執(zhí)行文件比較短小,并且當(dāng)共享對(duì)象被多個(gè)進(jìn)程使用時(shí)能節(jié)約一些內(nèi)存洽沟,因?yàn)樵趦?nèi)存中只需要保存一份此共享對(duì)象的代碼以故。但并不是使用動(dòng)態(tài)鏈接就一定比使用靜態(tài)鏈接要優(yōu)越。在某些情況下動(dòng)態(tài)鏈接可能帶來(lái)一些性能上損害裆操。

經(jīng)過(guò)上述五個(gè)過(guò)程怒详,C源程序就最終被轉(zhuǎn)換成可執(zhí)行文件了

上面5個(gè)步驟分別對(duì)應(yīng)了gcc的幾個(gè)選項(xiàng) -E -S -c 和 ld工具鳄乏, gcc的-o 選項(xiàng)可以看作是一個(gè)重定向選項(xiàng),和shell中的> 類比棘利, -o后面接的文件名就是輸出文件橱野, gcc的輸入文件一般放在命令的最后,或者放在-c的后面
gcc -E:是預(yù)處理選項(xiàng)善玫,比如 gcc -E main.c -o main.E 將會(huì)生成對(duì)應(yīng)源文件的匯編結(jié)果水援,注意預(yù)處理過(guò)程是不產(chǎn)生對(duì)應(yīng)的輸出文件的,它會(huì)將預(yù)處理后的內(nèi)容顯示到屏幕和輸送到編譯階段茅郎,所以如果需要保存預(yù)編譯的內(nèi)容蜗元,需要用-o選項(xiàng)進(jìn)行重定向保存
gcc -S:是編譯選項(xiàng),這個(gè)選項(xiàng)會(huì)將預(yù)處理好的源代碼編譯成匯編語(yǔ)言系冗,比如gcc -S main.c -o main.S 奕扣,注意 -S會(huì)默認(rèn)執(zhí)行-E選項(xiàng)的過(guò)程
gcc -c: 是匯編選項(xiàng),這個(gè)選項(xiàng)將源代碼匯編成對(duì)應(yīng)的目標(biāo)文件(*.o)掌敬,并且以源文件的前綴命名惯豆, 比如gcc -c main.c 將生成 main.o , gcc -c main.S 也將生成main.o文件, 當(dāng)gcc只有這個(gè)選項(xiàng)的時(shí)候?qū)⒛J(rèn)執(zhí)行前面的-E -S選項(xiàng)
ld: ld工具是連接工具奔害,ld -Tmain.lds 0x0000 main.o -o main 它將前面產(chǎn)生的目標(biāo)文件連接成可執(zhí)行文件楷兽,至于目標(biāo)文件,我們也可以使用ar工具或者gcc -shared 制作不同的靜態(tài)庫(kù)和共享庫(kù)
如果編譯一個(gè)源文件時(shí)华临,gcc沒(méi)有帶任何參數(shù)芯杀,那么會(huì)將上面的選項(xiàng)全部執(zhí)行

下面將用一個(gè)實(shí)際例子來(lái)解釋上面的幾個(gè)步驟:
(1) 首先編輯一個(gè)簡(jiǎn)單的文件 main.c

#include <stdio.h>  
#define A 1  
#define B 2  
  
int main()  
{  
    printf("a+b=%d \n", A, B);  
    return 0;  
}  

(2) 執(zhí)行g(shù)cc -E main.c -o main.i ,生成預(yù)處理文件main.i,下面是main.i的內(nèi)容

extern char *ctermid (char *__s) __attribute__ ((__nothrow__));  
# 886 "/usr/include/stdio.h" 3 4  
extern void flockfile (FILE *__stream) __attribute__ ((__nothrow__));  
  
  
  
extern int ftrylockfile (FILE *__stream) __attribute__ ((__nothrow__)) ;  
  
  
extern void funlockfile (FILE *__stream) __attribute__ ((__nothrow__));  
# 916 "/usr/include/stdio.h" 3 4  
  
# 2 "main.c" 2  
  
  
  
int main()  
{  
    printf("a+b=%d \n", 1, 2);  
    return 0;  
}  

可以看到預(yù)處理階段雅潭,將宏進(jìn)行了替換

(3)執(zhí)行g(shù)cc -S main.c -o main.s 將生成匯編文件main.s

    .file   "main.c"  
    .section    .rodata  
.LC0:  
    .string "a+b=%d \n"  
    .text  
.globl main  
    .type   main, @function  
main:  
    pushl   %ebp  
    movl    %esp, %ebp  
    andl    $-16, %esp  
    subl    $16, %esp  
    movl    $.LC0, %eax  
    movl    $2, 8(%esp)  
    movl    $1, 4(%esp)  
    movl    %eax, (%esp)  
    call    printf  
    movl    $0, %eax  
    leave  
    ret  
    .size   main, .-main  
    .ident  "GCC: (Ubuntu 4.4.3-4ubuntu5.1) 4.4.3"  
    .section    .note.GNU-stack,"",@progbits  

(4)執(zhí)行 gcc -c main.s -o main.o 將生成目標(biāo)文件 main.o

(5)執(zhí)行l(wèi)d -Tmain.lds -o main 將連接成可執(zhí)行文件 main
main.lds是連接腳本揭厚,它定義了整個(gè)程序編譯之后的連接過(guò)程,決定了一個(gè)可執(zhí)行程序的各個(gè)段的存儲(chǔ)位置扶供,
關(guān)于.lds 的內(nèi)容可自尋查找

轉(zhuǎn)載出處:http://blog.csdn.net/lee244868149/article/details/49536747

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末筛圆,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子诚欠,更是在濱河造成了極大的恐慌顽染,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件轰绵,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡尼荆,警方通過(guò)查閱死者的電腦和手機(jī)左腔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)捅儒,“玉大人液样,你說(shuō)我怎么就攤上這事振亮。” “怎么了鞭莽?”我有些...
    開(kāi)封第一講書人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵坊秸,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我澎怒,道長(zhǎng)褒搔,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任喷面,我火速辦了婚禮星瘾,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘惧辈。我一直安慰自己琳状,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布盒齿。 她就那樣靜靜地躺著念逞,像睡著了一般。 火紅的嫁衣襯著肌膚如雪边翁。 梳的紋絲不亂的頭發(fā)上肮柜,一...
    開(kāi)封第一講書人閱讀 49,772評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音倒彰,去河邊找鬼审洞。 笑死,一個(gè)胖子當(dāng)著我的面吹牛待讳,可吹牛的內(nèi)容都是我干的芒澜。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼创淡,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼痴晦!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起琳彩,我...
    開(kāi)封第一講書人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤誊酌,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后露乏,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體碧浊,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年瘟仿,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了箱锐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡劳较,死狀恐怖驹止,靈堂內(nèi)的尸體忽然破棺而出浩聋,到底是詐尸還是另有隱情,我是刑警寧澤臊恋,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布衣洁,位于F島的核電站,受9級(jí)特大地震影響抖仅,放射性物質(zhì)發(fā)生泄漏坊夫。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一岸售、第九天 我趴在偏房一處隱蔽的房頂上張望践樱。 院中可真熱鬧,春花似錦凸丸、人聲如沸拷邢。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)瞭稼。三九已至,卻和暖如春腻惠,著一層夾襖步出監(jiān)牢的瞬間环肘,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工集灌, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留悔雹,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓欣喧,卻偏偏與公主長(zhǎng)得像腌零,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子唆阿,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容