gdb除錯
對於平常的應用程式開發,我們很少關注編譯和鏈結過程,因為通常的開發環境都是整合開發環境(ide),比如visual studio,這樣的ide一般都將編譯和鏈結過程一步完成。接下來我們將神的了解編譯和鏈結的具體過程。
比如說現在有乙個main.c以及一些標頭檔案,現在我們使用gcc來編譯它。
預處理階段主要是源**.c檔案以及一些標頭檔案等被編譯成乙個.ii檔案,命令為:
gcc -e main.c -o main.i預編譯階段主要處理源**檔案中哪些以「#」開始的預編譯指令,比如「#include」,「#define」等,主要處理規則如下: 編譯的過程就是把與處理完的檔案進行一系列的詞法分析、語法分析、語義分析及優化後產生相應的彙編**檔案。命令為:
gcc -s main.i -o main.s彙編是將彙編**轉換成機器可以執行的指令,生成二進位制課重定位檔案。命令為:
gcc -c main.s -o main.o合併所有的obj檔案並進行符號的重定位。
鏈結的主要任務是將各個模組之間相互引用的部分都處理好,使得各個模組之間能夠正確的銜接。鏈結的過程主要包括位址和空間分配、符號決議和重定位。
位址被修訂的過程叫做重定位,使他們指向正確的位址。
詳細請見《程式設計師的自我修養》三、四章。
預編譯:gcc -e main.c -o main.i
編譯:gcc -s main.i -o main.s
彙編:gcc -c main.s -o main.o
__一步完成編譯:gcc -o main main.c __
-o是輸出的意思
一般的做法是先執行程式並觀察其輸出結果,如果不能正常工作,我們就需要決定採取哪種措施。程式除錯可分為以下五個階段:
接下來我將先通過乙個具體的例項來預先了解一下gdb除錯。
以下為源程式:
#include
intfun
(int n)
return sum;
}int
main()
printf
("redult[1-100] = %d\n"
, result)
;printf
("redult[1-250] = %d\n"
,fun
(250))
;return0;
}
將源程式編譯生成可執行檔案:gcc -o main main.c-g<1>啟動gdb:
gdb main //啟動gdb執行之後顯示如下:
要退出除錯介面,按「quit」即可。
<2>列出程式源**
使用「list」命令可列出源**,常簡寫為「l」,若執行之後**未完全顯示,可按回車鍵繼續重複執行上乙個命令。
<3>設定斷點
有許多命令可以設定斷點,用命令「help breakpoint」可列出,如下所示:
比如說我在某行設定乙個斷點,命令為b+行號(break可簡寫為b)
b 16
若是b+函式名,則表示在函式入口點加斷點,如下所示
b fun
如果想檢視所加斷點的資訊,可以使用命令info break
在這兒,使用命令delete+num(斷點編號)可以刪除斷點
<4>執行程式
命令為r(run的簡寫)
程式在執行到所加的斷點時會停住,此時再執行命令n(next的簡寫,單條語句執行)
之後再執行命令c(continue的簡寫),會輸出最後結果。如下所示:
在設定的斷點之後可以列印變數的值,使用命令p(print的簡寫)
bt顯示函式呼叫棧關係
s進入函式
finish跳出函式
最後退出gdb除錯,q。
詳細可檢視
編譯鏈結過程
在談編譯鏈結過程之前我們需要了解一下虛擬位址空間以及程式在編譯鏈結過程時經過了什麼步驟。虛擬位址空間之前在程序空間的部落格中詳細介紹過了,詳見 上圖就是32位系統中4g虛擬位址空間的分布情況 text 段 指令段,存放的是指令 在程式中,我們把區域性變數定義 區域性變數的 定義是指令而不是資料 還有...
編譯鏈結過程(一)
什麼是編譯?什麼是鏈結?為什麼需要編譯和鏈結?在很久以前,計算機發展的初期,還在用機器語言編寫程式,量比較少時是不需要編譯和鏈結的。因為當時的程式設計師直接編寫機器碼讓計算機執行。每種cpu的指令是不相同的,所以每乙個程式要換一台不同cpu的機器上執行時,需要重新寫程式,而且機器語言 涉及很多計算機...
編譯鏈結過程(二)
前一篇博文提到編譯的幾個步驟,這一篇來了解下具體每一步都幹了些什麼,好叫心裡有數。詳細的過程,我想只有通過分析乙個具體的編譯器 才好。下面介紹的幾個步驟完成了原始碼檔案經過編譯鏈結後成為可執行檔案 預編譯後的檔案,不再包含注釋,標頭檔案也插入進來,條件編譯也得到相應的處理。那麼,剩下的就是實實在在的...