導航:首頁 > 源碼編譯 > 預編譯和連接

預編譯和連接

發布時間:2022-08-15 13:21:16

A. 用gcc編譯器C語言程序的技巧

方法/步驟
1、編寫c代碼,並輸入以下代碼,生成文件hello.c
[root@wahoo
test]#
vim
hello.c
#include
<stdio.h>
#define
DISPLAY
"hello
c!"
int
main(void)
{
printf("%s\n",
DISPLAY
);
return
0;
}
ZZ(說明:ZZ當前文件進行快速保存操作)
2、預編譯(Preprocessing)
會對各種預處理指令(#include
#define
#ifdef
等#開始的代碼行)進行處理,刪除注釋和多餘的空白字元,生成一份新的代碼
[root@wahoo
test]#gcc
-E
hello.c
-o
hello.i
E
參數
通知gcc對目標文件進行預編譯,這里是對文件hello.c文件
o
參數
是對命令輸出結果進行導入操作,這里是把
gcc
-E
hello.c
操作結果輸出到文件hello.i(命名要自定義)中進行保存
這個命令執行完後我們目錄下多了一個文件hello.i,你可以查閱一下文件的內容。
3、編譯(Compilation)
對代碼進行語法、語義分析和錯誤判斷,生成匯編代碼文件
[root@wahoo
test]#gcc
-S
hello.i
-o
hello.s
S
參數
通知gcc對目標文件進行編譯,這里是對文件hello.i文件
通過這一步我們知道
C語言跟匯編的
關系,至於他們之前是如何進行轉換的,大家可以進行更深入的學習與探討。
此時目錄下多了一個hello.s文件,內容如圖
4、匯編(Assembly)
把匯編代碼轉換與計算機可認識的二進制文件,要知道計算機只認識0和1呢
[root@wahoo
test]#gcc
-c
hello.s
-o
hello.o
c
參數
通知gcc對目標文件執行指令轉換操作
此步驟我們得到文件hello.o
大家也同樣打開文件查看一下,這個文件裡面幾乎沒幾個字元大家能看懂,這就對了,但大家可以通過這種方法將其轉化為我們可讀的形式:
[root@wahoo
test]#readelf
-a
hello.o
5、鏈接(Linking/Build)
通俗的講就是把多個*.o文件合並成一個可執行文件,二進制指令文件
[root@wahoo
test]#gcc
hello.o
-o
hello
這里我們就得到了一個可以直接在系統下執行的文件
hello
我們也可以對這個文件進行readelf操作,也可以進行二進制指令轉匯編的操作
[root@wahoo
test]#objmp
-d
hello
6、程序運行
[root@wahoo
test]#./hello
hello
c!
7、總結:gcc
編譯c程序的主要過程包括
預編譯->編譯->匯編->連接
四個過程,每個過程都分別進行不同的處理,了解了這其中的一些原理,對c編程的理解大有益處

B. 在C語言中,完成C源文件編輯後到生成執行文件的步驟是什麼

在C語言中,完成C源文件編輯後到生成執行文件的步驟是:

  1. 預編譯

    處理有#標識的代碼,如將include的文件進行拷貝、#define的條件編譯等等!

  2. 編譯

    編譯就是將第一階段處理得到的文件通過詞法語法分析等轉換為匯編,對目標代碼的生成進行的優化,翻譯成機器指令。生成的文件叫目標文件。

  3. 鏈接

    把目標文件和所需要的庫,鏈接成為可執行文件。

C. 如何實現c語言程序的連接

一、C語言源程序文件經過編譯連接之後生成一個後綴為
.exe
的文件。
二、編譯,編譯程序讀取源程序(字元流),對之進行詞法和語法的分析,將高級語言指令轉換為功能等效的匯編代碼,再由匯編程序轉換為機器語言,並且按照操作系統對可執行文件格式的要求鏈接生成可執行程序。
1、預編譯,對源代碼的宏進行替換,生成中間文件(文本,默認不保留)。
2、翻譯為匯編代碼(文本,默認不保留)。
3、由匯編器生成二進制文件(.obj)。
4、連接為可執行文件(.exe)。

D. C文件如何成為可執行文件(編譯、鏈接、執行)——摘自《程序員的自我修養》

本文算是我閱讀《程序員的自我修養》(俞甲子等著)相關章節的筆記,文中直接引用了原書中的敘述,強烈建議大家去看原書,本文只做概要介紹而用。——註:文中有很多引用圖的地方,請大家自己去找原書看,支持正版!我遇到一個問題,Linux C編程中的問題:.. char *p; unsigned int i = 0xcccccccc; unsigned int j; p = (char *) &i; printf("%.2x %.2x %.2x %.2x\n", *p, p[1], p[2], p[3]); memcpy(&j, p, sizeof(unsigned int)); printf("%x\n", j); ... Output: ffffffcc ffffffcc ffffffcc ffffffcc 0xcccccccc My questions are: 1. Why it prints "ffffffcc ffffffcc ffffffcc ffffffcc"? (if p is unsigned char* then it will print correctly "cc cc cc cc") 2. Why pointer to char p copied to j correctly, why not every member in p overflow? since it is a signed char. 這是別人在郵件列表中提出的問題,在試圖回答這個問題的過程中,突然發現,自己對連接器的工作並不熟悉,因此拿來好書《程序員的自我修養》來看,並做如下匯報,強烈推薦《程序員的自我修養》!!!寫好的C語言文件,最終能夠執行,大致要經過預處理、編譯、匯編、鏈接、裝載五個過程。預編譯完成的工作: (1)將所有的"#define"刪除,並展開所有的宏定義 (2)處理所有條件預編譯指令 (3)處理#include預編譯指令,將被包含的文件插入到預編譯指令的位置,這個過程是遞歸進行的。 (4)刪除所有的注釋 (5)添加行號和文件名標識,以便調試 (6)保留所有的#pragma編譯器命令,因為編譯器需要使用它們。編譯完成的工作: (1)詞法分析 掃描源代碼序列,並將其分割為一系列的記號(Token)。 (2)語法分析 用語法分析器生成語法樹,確定運算符號的優先順序和含義、報告語法錯誤。 (3)語義分析 靜態語義分析包括生命和類型的匹配,類型的轉換;動態語義分析一般是在運行期出現的與語義相關性的問題,如除0錯。 (4)源代碼生成 源代碼級優化器在源代碼級別進行優化:如將如(6+2)之類的表達式,直接優化為(8)等等。將語法書轉換為中間代碼,如三地址碼、P-代碼等。 (5)代碼生成 將源代碼轉換為目標代碼,依賴於目標機器。 (6)目標代碼優化匯編完成的工作: 將匯編代碼變成機器可以執行的指令鏈接完成的工作: 鏈接完成的工作主要是將各個模塊之間相互引用的部分處理好,使得各個模塊之間正確銜接。鏈接過程包括:地址和空間分配、符號決議和重定位。 首先講靜態鏈接,基本的靜態鏈接如下: 我們可能在main函數中調用到定義在另一個文件中的函數foo(),但是由於每個模塊式單獨編譯的,因此main並不知道foo的地址,所以它暫時把這些調用foo的指令的目標地址擱置,等到最後鏈接的時候讓連接器去修正這些地址(重定位),這就是靜態鏈接最基本的過程和作用;對於定義在其他文件中的變數,也存在相同的問題。具體過程如下: (1)空間和地址分配 1)空間與地址分配:掃描所有輸入目標文件,獲得各個段的屬性、長度和位置,並且將目標文件中的符號表中所有的符號定義和符號引用收集起來,放到一個全局符號表中。 2)符號解析和重定位:使用第一步收集到的信息,讀取輸入文件中段的數據、重定位信息,並進行符號解析與重定位、調整代碼中的地址等。 動態鏈接的過程更為復雜,但是完成的工作類似。 動態鏈接的初衷是為了解決空間浪費和更新困難的問題,把鏈接過程推遲到運行時進行 首先介紹一個重要的概念——地址無關代碼。為了解決固定裝載地址沖突的問題,我們希望對所有絕對地址的引用不作重定位,而把這一步推遲到裝載的時候再完成,一旦模塊裝載地址確定,即目標地址確定,那麼系統對程序中所有的絕對地址引用進行重定位。同時我們希望,模塊中共享的指令部分在裝載時不需要因為裝載地址的改變而改變,所以把指令中那些需要被修改的部分分離出來,跟數據放在一起,這樣指令部分就可以保持不變,而數據部分可以在每個進程中擁有一個副本,這種方案目前被稱為地址無關代碼(PIC,Position-independent Code)。 我們需要解決如下四種引用中的重定位問題: 1)模塊內部調用或者跳轉:這個可以用相對地址調用或者基於寄存器的相對調用,所以不需要重定位2)模塊內部數據的訪問:用相對定址的方法,不過鏈接器實現得十分巧妙: call494 <__i686.get_pc_thunk.cx> add$0x188c, %ecx mov$0x1, 0x28(%ecx) //a=1 調用一個叫做__i686.get_pc_thunk.cx的函數,把call的下一條指令的地址放到ecx寄存器中,接著執行一條mov指令和一個add指令3)模塊間數據的訪問:在數據段里建立一個指向全局變數的指針數組,也成全局便宜表(GOT),當要引用全局變數時,可以通過GOT相對應的項間接引用: GOT是做到指令無關的重要的一環:在編譯時可以確定GOT相對於當前指令的偏移,根據變數地址在GOT中的偏移就可以得到變數的地址,當然GOT中哪個每個地址對應於哪個變數是由編譯器決定的。4)模塊間的調用、跳轉:採用上面類似的方法,不同的是GOT中相應的項存儲的是目標函數的地址,當模塊需要調用目標函數時,可以通過GOT中的項進行間接跳轉。 地址無關代碼小結: 現在,來看動態鏈接中的另一個重要問題——延遲綁定(PLT)。當函數第一次被用到時才進行綁定,否則不綁定。PLT為了實現延遲綁定,增加了一層間接跳轉。調用函數並不是通過GOT跳轉的,而是通過一個叫PLT項的結構進行跳轉的,每個外部函數在PLT中都有對應的項,如函數bar,其在PLT對應的項的地址記為bar@plt,實現方式如下: bar@plt: jmp* (bar@GOT) pushn pushmoleID jump_dl_runtime_resolve 鏈接器的這個實現至為巧妙: 如果在連接器初始化階段,已經正確的初始化了bar@GOT,那麼這個跳轉指令的結果正是我們所期望的,但是,為了實現PLT,一般在連接器初始化時,將"pushn"的地址放入到bar@GOT中,這樣就直接跳轉到第二條指令,相當於沒有進行任何操作。第二條指令「pushn」,n是bar這個符號引用在重定位表「.rel.plt」中的下標。接著將模塊的ID壓棧,跳轉到_dl_runtime_resolve完成符號解析和重定位工作,然後將bar的地址填入到bar@GOT中。下次再調用到bar時,則bar@GOT中存儲的是一個正確的地址,這樣就完成了整個過程。 在鏈接完成之後,就生成了你要的可執行文件了,如ELF文件,至於這個文件的詳細的信息,可以參考相關的文檔。 現在,你要運行你的可執行文件,這是如何做到的呢? 我們從操作系統的角度來看可執行文件的裝載過程。操作系統主要做如下三件事情:(1)創建一個獨立的虛擬地址空間,但由於採用了COW機制,這里只是復制了父進程的頁目錄和頁表,甚至不設置映射關系(參考操作系統相關書籍)。(2)讀取可執行文件頭,並且建立虛擬空間與可執行文件的映射關系。(3)將CPU的指令寄存器設置成可執行文件的入口地址,啟動運行。我們來看一下執行過程中,進程虛擬空間的分布。 首先我們來區分Section和Segment,都可以翻譯為「段」,那麼有什麼不同呢?從鏈接的角度來講,elf文件是按照Section存儲的,從裝載的角度講,elf文件是按照Segment存儲的。」Segment」實際上是從裝載的角度重新劃分了ELF的各個段,將其中屬性相似的Section合並為一個Segment,而系統是按照Segment來映射可執行文件的。

E. c語言裡面的編譯和鏈接是怎麼回事

C/C++語言的完整編譯過程是

一、預編譯

處理#define #if #include這類#開頭的語句,這些稱為預編譯指令。這個過程中會把.h文件和.c/.cpp文件組合成最終交給compile過程的原文件。這個原文件是不包含任何#開頭的語句的。所有#define定義的宏也會被替換。

二、編譯
把上面那個原文件編譯成.o或者VC里是.obj文件。這個文件保存了機器碼化的函數、函數的描述、全局變數的描述、乃至段的描述等等。

三、連接
把可執行程序需要的所有的編譯過程產生的.o或者.obj文件組合到一起。(這里也包括.lib文件,.lib文件件本質上就是打包的.obj文件集合)。另外連接過程還會組合一些其他數據,比如資源、可執行文件頭等等。

F. C語言源程序的編譯過程包括哪三個階段

編譯:將源程序轉換為擴展名為.obj的二進制代碼
連接:將obj文件進行連接,加入庫函數等生成可執行文件
運行:執行可執行文件,有錯返回修改,無錯結束

G. c語言一次完成編譯、連接和執行用什麼鍵

C/C++語言的完整編譯過程是 一、預編譯 處理#define #if #include這類#開頭的語句,這些稱為預編譯指令。這個過程中會把.h文件和.c/.cpp文件組合成最終交給compile過程的原文件。這個原文件是不包含任何#開頭的語句的。所有#define定義的宏也會被替換。 二、編譯把上面那個原文件編譯成.o或者VC里是.obj文件。這個文件保存了機器碼化的函數、函數的描述、全局變數的描述、乃至段的描述等等。 三、連接把可執行程序需要的所有的編譯過程產生的.o或者.obj文件組合到一起。(這里也包括.lib文件,.lib文件件本質上就是打包的.obj文件集合)。另外連接過程還會組合一些其他數據,比如資源、可執行文件頭等等。

H. C語言文件的編譯與執行的四個階段並分別描述

開發C程序有四個步驟:編輯、編譯、連接和運行。

任何一個體系結構處理器上都可以使用C語言程序,只要該體系結構處理器有相應的C語言編譯器和庫,那麼C源代碼就可以編譯並連接到目標二進制文件上運行。

1、預處理:導入源程序並保存(C文件)。

2、編譯:將源程序轉換為目標文件(Obj文件)。

3、鏈接:將目標文件生成為可執行文件(EXE文件)。

4、運行:執行,獲取運行結果的EXE文件。

(8)預編譯和連接擴展閱讀:

將C語言代碼分為程序的幾個階段:

1、首先,源代碼文件測試。以及相關的頭文件,比如stdio。H、由預處理器CPP預處理為.I文件。預編譯的。文件不包含任何宏定義,因為所有宏都已展開,並且包含的文件已插入。我歸檔。

2、編譯過程是對預處理文件進行詞法分析、語法分析、語義分析和優化,生成相應的匯編代碼文件。這個過程往往是整個程序的核心部分,也是最復雜的部分之一。

3、匯編程序不直接輸出可執行文件,而是輸出目標文件。匯編程序可以調用LD來生成可以運行的可執行程序。也就是說,您需要鏈接大量的文件才能獲得「a.out」,即最終的可執行文件。

4、在鏈接過程中,需要重新調整其他目標文件中定義的函數調用指令,而其他目標文件中定義的變數也存在同樣的問題。

I. 在java中如何實現預編譯

/*
* ProCompile.java *預處理要編譯的文件,刪除多餘的空白,注釋,換行,回車等
* Created on 2007年9月18日, 下午8:58 */ package javacompile; import java.io.*;
import java.util.regex.*;
import javax.swing.JOptionPane; /** * @com.junjian.sun public class PerCompile { File f = null;
String fileString = null;
Pattern p = null;
Matcher m = null;
String regex; //正則表達式 //初始化p
public PerCompile() {
regex ="(//.+)" + //(//.+) 對應單行注釋
//"|(/\\*(.+\\n)+\\*/)"+ // 想對應多行注釋... "|(\\r\\n)" + "|(\\n)"+//(\\r\\n)|(\\n)對應換行
"|(\\B\\s+)" ; // 空白符
String ss;
f = new File(new JOptionPane()
.showInputDialog("請輸入文件所在路徑~"));
try {
BufferedReader bf = new BufferedReader(new FileReader(f));
ss = bf.readLine()+"\n";
fileString = ss; //如果沒有這兩句,ss的開頭會有「null」
while((ss = bf.readLine())!= null){
fileString += ss+"\n"; bf.close();
} catch (IOException ex) {
ex.printStackTrace(); p = Pattern.compile(regex);
m = p.matcher(fileString); //執行替換所有多餘空行,空白符,注釋
void Dels(){
System.out.println("before: "+fileString);
if(m.find()) System.out.println("find!!");
System.out.println(m.replaceAll("")); } }

-

J. c語言裡面的編譯和鏈接是怎麼回事啊

C/C++語言的完整編譯過程是

一、預編譯

處理#define #if #include這類#開頭的語句,這些稱為預編譯指令。這個過程中會把.h文件和.c/.cpp文件組合成最終交給compile過程的原文件。這個原文件是不包含任何#開頭的語句的。所有#define定義的宏也會被替換。

二、編譯
把上面那個原文件編譯成.o或者VC里是.obj文件。這個文件保存了機器碼化的函數、函數的描述、全局變數的描述、乃至段的描述等等。

三、連接
把可執行程序需要的所有的編譯過程產生的.o或者.obj文件組合到一起。(這里也包括.lib文件,.lib文件件本質上就是打包的.obj文件集合)。另外連接過程還會組合一些其他數據,比如資源、可執行文件頭等等。

閱讀全文

與預編譯和連接相關的資料

熱點內容
壓縮圖片壓縮 瀏覽:74
美國發明解壓魔方 瀏覽:300
電腦怎麼備案網上伺服器 瀏覽:513
旅行商問題Python寫法 瀏覽:951
解壓破壞王裡面的所有兌換碼 瀏覽:859
文件夾如何拖拽還保留原來的 瀏覽:21
職業生涯pdf 瀏覽:954
ubuntu安裝軟體php 瀏覽:159
黑馬程序員退學流程 瀏覽:362
網頁伺服器崩潰怎麼回事 瀏覽:651
cnc編程前景怎麼樣 瀏覽:320
lniux命令詳解 瀏覽:494
linuxmysql查詢日誌 瀏覽:369
老捷達夥伴壓縮比 瀏覽:94
改後綴加密 瀏覽:433
郵局選址問題演算法 瀏覽:15
河北伺服器內存雲主機 瀏覽:13
在電腦上怎麼找到加密狗圖標 瀏覽:438
電腦的瀏覽器怎麼打開pdf文件怎麼打開 瀏覽:145
pdf卡片庫下載 瀏覽:14