1. 程式人生 > >Linux下編輯、編譯、除錯命令總結——gcc和gdb描述

Linux下編輯、編譯、除錯命令總結——gcc和gdb描述

GCC

  gcc是linux系統整合的編譯器。在linux環境下編輯程式,首先需要克服的便是沒有整合開發環境的一鍵式操作所帶來的麻煩。這其中涉及命令列操作、編譯選項的設定、檔案依賴關係的書寫(makefile)等問題。這裡主要介紹的是關於gcc的常用命令列引數及其相應的作用。(若編譯C++檔案,則只需將下列命令的 gcc 換為 g++,原始檔的字尾應為 .C/.cpp/.c++/.cc等)

基本格式:gcc [options] file1 file2… //若不加入引數,則按預設引數依次執行編譯、彙編和連線操作,生成的可執行檔名為 a.out
常用引數:-E //只執行預處理操作
     -S //只執行到編譯操作完成,不進行彙編操作,生成的是彙編檔案(.s 或 .asm),內容為組合語言
     -c //執行編譯和彙編,但不進行連結,即只生成可重定位目標檔案(.o),為二進位制檔案,不生成完整的可執行檔案
     -o filename //將操作後的內容輸出到filename指定的檔案中
     -static //對於支援動態連結的系統,使用靜態連結而不是動態連結進行連結操作
     -g          //編譯時生成debug有關的程式資訊(供gdb使用)
     –save-temps //生成編譯過程的中間結果檔案(包括預處理檔案(x.ii)、彙編程式碼(x.s)、目標檔案(x.o)和最終的可執行檔案)

     -I PATH //在PATH指定的目錄下尋找相關的include檔案
     -lxx //其中xx為指定函式庫,對於Linux環境下的函式庫,靜態庫字尾為.a,動態庫字尾為.so,一般庫名為libxx.a或libxx.so,如加入libm.so庫,則使用引數-lm(去除lib和字尾.a\so)
     -L PATH //在PATH指定的目錄下尋找相關的庫檔案,即-lxx指定待連結的庫,-L指定尋找該庫的路徑。不指定時搜尋預設的庫函式路徑。
     -std=xx //指定編譯使用的語言標準
     -x language //指定待編譯檔案的語言,而不是由編譯器根據檔案字尾自行判斷。即預設情況下gcc根據檔案字尾判斷使用的程式語言。例如使用檔名hello作為原始檔名是不合適的,應使用hello.c
     
     -Wall //輸出一些簡單的錯誤以及一些可能存在問題的警告
     -Wextra //輸出-Wall不包含的警告等
     -Werror //將警告視為錯誤輸出
     
     -D name=definition //加入巨集定義,若不指定def,則預設為1
     -O1、-O2       //規定編譯器的優化等級,優化級數越高執行效率一般越好,但是優化會改變原有程式結構,使得其彙編不易理解

     //一些進行緩衝區溢位實驗時可能需要的選項
     -fstack-protector-fno-stack-protector  //是否開啟堆疊保護,這裡的保護是在返回地址之前加入一個驗證值來確保返回地址不被破壞
     -z execstack                  //啟用可執行棧,預設是禁用的
     //(echo 0 >/proc/sys/kernel/randomize_va_space 關閉地址隨機化,這是一個單獨的命令,操作需要root許可權)
複製程式碼
  舉例說明

  (1)將原始檔編輯為可執行檔案

gcc hello.c  //預設生成名為a.out的可執行檔案,這樣若在同一資料夾下編譯另一個程式,則會a.out會被後來檔案覆蓋

  (2)編譯檔案,並輸出到hello.s

gcc -S -o hello.s  hello.c

  (3)生成兩個可重定位目標檔案

gcc -c hello.c world.c    //生成hello.o與world.o,不進行連結操作,即僅進行預處理、編譯、彙編,而不進行連結

  (4)對庫檔案、目標檔案進行連線操作

gcc -static hello.o world.o -lm -L /usr/lib     //以靜態連結的方式,將hello.o、world.o以及libm.a庫中的相關目標檔案連結,在/usr/lib資料夾下尋找目標庫

GDB

  gdb是Linux下一款功能強大的除錯工具,它既能在反彙編過程中充當一件稱手的工具,也能在程式debug過程中為為程式設計師提供幫助,其唯一美中不足的是在Linux環境下沒有影象介面(當然沒有功能的封裝也是其功能強大的原因之一,而且現在的ddd也提供了GUI)。這裡主要記錄筆者從一些學習指導中學習的關於gdb命令和用法的總結。

  為什麼要使用GDB?

  1.在Windows環境下,許多IDE以圖形介面提供類似gdb的功能,一般也較為好用。但是一方面,gdb提供給使用者更大的自由,另一方面gdb也是目前幾乎所有Linux發行版本的自帶軟體,簡單易得;

  2.除錯程式時儘量減少對諸如printf等輸出函式的依賴。許多作者給出的解釋是重新修改程式碼和編譯是一件麻煩的差事。這一點筆者起初也並不理解,覺得上述操作確實不算麻煩(…)。後來發現,對於一個單一檔案,程式碼不超過100行的檔案,上述操作確實在可接受範圍。但對於檔案眾多,工程量巨大的專案,修改程式碼、重新編譯檔案是一件極其耗時且麻煩的操作。如果在Windows環境下進行大工程的debug所需要的修改、重編譯所帶來的頻繁滑鼠或快捷鍵操作還不能使你回心轉意的話,相信我,在Linux的命令列模式下進行相同的操作會讓你有所改變的;

  3.習慣是逐漸養成的,不論好壞都是。或許只有逐漸在看起來不那麼方便的GDB中鍛鍊起來,你才能在無論什麼編譯環境中debug的得心應手,可能那時,你會嫌棄圖形介面提供的工具不夠給力的;

  除錯策略

  無論進行何種除錯工作,大體的除錯策略都類似:使用二分法的方式對錯誤地點進行定位;使用斷點(breakpoint),使程式執行至斷點處時停止以便觀察程式狀態;使用單步執行,使程式執行一條指令後停止,從而觀察資料的變化情況和程式控制流;對一個變數預設特定的值,跟蹤其在程式執行中的變化規律等等。根據二八定律,使用20%的GDB指令,一般就可以解決80%的程式bug。這裡介紹的是能夠常規使用GDB的命令,更多高階或特殊指令,可以參考GDB官方文件Degugging with GDB。

  為了更好的使用gdb的除錯功能,在編譯程式時需加入 -g 選項,由編譯器生成某些用於除錯的資訊。

  GDB常用命令(此部分譯自 Guide to Faster,Less Frustrating Debugging,細節有改動)

  開始/結束gdb

  使用 gdb filename 啟動gdb,其中 filename 應為可執行檔案。

gdb a.out    //使用gdb對a.out進行除錯  

  gdb以命令列環境執行,進入gdb後,程式會等待使用者的指令並執行,直至使用者選擇退出。使用 q 或 Ctrl + d 退出。

  執行(r)指令

  使用命令 r 執行(run)程式,另外也可以加入程式執行所需要的引數,若原命令列模式下的執行指令為 ./a.out > test.txt ,則在gdb執行時應為 r > test.txt。且如果在同一除錯過程中需要多次執行程式(run),後續再執行時便可直接使用 r 指令,系統會預設使用之前的引數。

  r              //執行程式
  r [options] arguments  //帶引數執行程式,引數與命令列環境下一致,使用 r 替換源程式檔案即可

  List( l )指令

  可以使用指令 l 來列出原始檔中的部分原始碼。(需要編譯時加入 -g 選項生成對應的編譯符號)

 l 10   //輸出源程式10行及前後幾行的原始碼,可以方便進行除錯。若要繼續檢視,按回車鍵會繼續向下顯示。

  對於多個檔案的而言,可以通過 l source_file_name.c:col (l 原始檔名:行號)來指定所需檢視的原始碼

 l hello.c:10  //輸出hello.c在10行前後的程式碼

  也可以以函式為整體進行輸出,命令格式為 l function_name

 l main     //輸出main函式的原始碼

  斷點(b)和繼續執行(c)指令

  指令 b 可以在需要地方放置斷點,使得程式在指令的位置停止執行,指令格式為 b 斷點位置。其中,斷點位置可以是行號,也可以是函式名(指定方式與 l 指令類似),也可以是地址。

  b 10        //在原始碼10行處放置斷點
  b main       //在main函式開始處放置斷點
  b 0x80480000   //在存放在0x80480000處的指令處放置斷點,直接使用地址時需要使用 地址 的格式
  b 10 if a<10    //可以在斷點中加入中斷執行的條件,表示當a < 10 時才會中斷程式執行
  在斷點處檢查完畢後,可以使用 c 指定繼續指令的執行。使用指令 disable/enable 斷點號 可以啟用/停用某斷點。使用指令 d 可刪除所有的斷點,d 1 刪除breakpoint 1.

disable/enable    n        //停用/啟用編號為n的斷點
d                //刪除所有斷點
d    n           //刪除標號為n的斷點

  觀測點(watch)指令

  指令watch可以為某一表達式設定觀察點,當程式執行過程中,當表示式的值發生改變時,則 gdb 會中斷程式執行,並顯示錶達式的變化情況。

  watch a      //當變數 a 的值發生變化時,中斷程式執行
  watch -l a    // watch指令指定了 -l 引數時,會將指令所接的表示式的計算結果作為地址,觀察該地址處的值的變化情況
  rwatch a     // 當 a 的值被讀取時,中斷表示式的執行
  

  顯示(disp)和列印(p)指令

  disp指令(display)可以在每次程式暫定時顯示指定變數的值,指令格式為 disp 變數名。若輸入的變數為陣列名,則每次顯示陣列的所有元素,若為結構體,則輸出結構體的所有成員的值。

  disp temp     //在每次程式暫停時輸出指定的變數的值(確保程式在指定變數的作用域內執行,如某個在特定函式中的區域性變數在程式進入該函式執行之前是無法被顯示的)
  undisplay     //取消所有disp指定的自動顯示變數
  p指定(print)同樣將變數的值打印出來,用法與diap類似,但結果只顯示一次。

  除變數外,p指令還可以輸出給定暫存器、給定地址處的值。同時,可以通過一些引數對列印格式進行規定,如 /x 表示以16進位制格式列印值,/t表示以二進位制格式列印值。

  p eax//標誌暫存器名稱
  p /x ($ebp + 8)  //以十六進位制的格式列印%ebp + 8 的值
  p /t 100      //以二進位制格式輸出100的值
  p 0x08048000   //輸出位於0x08048000處的資料(此處實際存放的是機器程式碼),注意地址需使用 標誌,否則會被預設為常數
  p (int )0xxxxxxxx //將指定地址處資料按照整數格式輸出,這裡一般需要指出指標型別方便gdb解釋資料
  

  其他顯示類info命令

  info reg      //輸出所有暫存器的當前值
  info frame     //輸出棧幀的使用情況
  info b n     //其中 n 為指定的斷點號,顯示指定斷點的狀態資訊,不加引數 n 時,會顯示所有的斷點的資訊
  

  記憶體檢查(examine)指令

  x 指令用於檢查記憶體中某一區域的值,指令格式為 :x fmt address 。其中address為記憶體地址的表示式,fmt由 /重複次數+格式化字元+尺寸字元 組成。格式化字元有o(octal,八進位制),x(hex,十六進位制), d(decimal,十進位制),u(unsigned decimal,無符號十進位制),t(binary,二進位制),f(float,浮點),a(address,地址),i(instruction,指令),c(char,字元),s(string,字串).尺寸字元有 b(byte),h(halfword), w(word), g(giant, 8 bytes)

x /4xb *0xxxxxx  //將指定地址區域連續的四個位元組以十六進位制的格式輸出,一般記憶體地址均使用 * 標識

  格式化輸出(printf)指令

  該指令的使用方法與C語言中的格式化輸出函式相似

printf" %d , %d \n",X,Y  //對於兩個變數整形X,Y進行輸出

  使用指令whatis可以方便的得知所需物件的型別,如 whatis temp 會顯示出temp的型別定義,在除錯時有用。

  執行(s與n)指令

  s 與 n 指令都是表示執行下一條指令指令的意思。但是,當遇到函式呼叫時,s 指令會進入函式呼叫內部進行執行,即下一步為被調函式的第一指令,而 n 指令不進入函式呼叫內部,會將整個函式的執行過程當作一步執行。

  回溯(bt)指令

  回溯指令(backtrace)可以檢視程式記憶體訪問越界等錯誤資訊,顯示程式出錯的位置,從而幫助定位程式錯誤。

  設定(set)指令

  設定指令 set 可以將指定的變數的值修改為除錯所需要的值。如對於一個int型的變數X,可以使用 set X = 12 將變數的值進行設定。

  使用巨集定義

  可以使用巨集定義對一些常用指令進行定義。指令格式 :define 巨集名,並根據提示輸入巨集定義,以end作為結尾標誌。

  另外,在使用gdb進行除錯過程中,可能免不了需要重新編譯程式,這時不必將gdb退出,只需待程式重新編譯後使用 r 指令重新執行程式,gdb會自動更新程式狀態,這樣可以節約時間。

相關推薦

Linux編輯編譯除錯命令總結——gccgdb描述

GCC   gcc是linux系統整合的編譯器。在linux環境下編輯程式,首先需要克服的便是沒有整合開發環境的一鍵式操作所帶來的麻煩。這其中涉及命令列操作、編譯選項的設定、檔案依賴關係的書寫(makefile)等問題。這裡主要介紹的是關於gcc的常用命令列引

linux使用eclipse編譯連結動態庫的學習筆記

 一、建立動態連結庫     1、建立工程new->project->c++ project選擇Shared Library->Empty Project.輸入工程名MySharedLib,點選finish,完成工程的建立。   2. 庫程式碼的

linux編輯編譯執行C/C++/python程式

1,C和C++程式 http://www.2cto.com/kf/201207/140035.html http://blog.chinaunix.net/uid-20620288-id-3217203.html 其中,如果hello.c 程式中含有數學函式,用gcc編譯

LINUX安裝Python3.7Pycharm[Linux命令記錄]

有道 空白 命令格式 type 活動 user 界面 org n天前 環境   阿裏雲CenterOs7.4 64位 + Python3.7.0 + pycharm-professional-2018.3 安裝Python   1. 安裝依賴包 sudo yum -y g

Linux環境openssl交叉編譯安裝裁剪

最近的專案需求中依賴libcrypto和libssl庫,所以需要編譯安裝openssl0.9.8e,花了差不多一天的時間終於成功安裝和裁剪,現在總結並分享個人的方法,貼出來供大家參考和指正。 方法如下(不同的平臺要根據實際環境更改相應的編譯工具): 一、配置: ./conf

Ubuntu14.04C++程式編輯編譯執行入門篇

初次接觸Ubuntu,一腦子的糊塗,更別提如何在Ubuntu下編譯執行C++程式了,經過查資料,下面是自己在Ubuntu下寫的第一個C++程式,僅供初學者參考,也為自己的入門學習梳理下思路。 1、輸入組合鍵“Ctrl+Alt+t”調出終端; 2、需要在當前目錄下建立一個.c

ubuntu/linux打包壓縮war解壓war包jar命令

把project_a資料夾下的檔案打包成project.war 1.      打包 jar -xvf project.war /project_a -c  建立war包 -v  顯示過程資訊 -f  指定 JAR 檔名,通常這個引數是必須的 -M  不產生所有項的清單

linux檔案的複製移動與刪除命令為:cp,mv,rm

檢視centOS 版本              cat /etc/redhat-release 1,複製貼上檔案  cp  [選項]  原始檔或目錄  目標檔案或目錄 2,剪下貼上檔案  mv [選項]  原始檔或目錄  目標檔案或目錄 3,刪除檔案    rm 檔案      慎用 rm -rf

完整版linuxandroid原始碼下載編譯模擬器啟動執行

一、環境說明: 1、VMware版本:8.0.3 build-703057 2、liunx系統:Ubuntu10.10 3、jdk:sun-java6-jdk 二、Ubuntu 10.10更新源列表       由於Ubuntu 10.10版本的源已經過期了,所以,需要

使用Visual Studio Code搭建Windows的Postgresql編譯除錯環境

一、Visual Stdio Code作為微軟近期推出的跨平臺程式碼編寫工具,今年已經推出C/C++語言外掛,可以進行C/C++語言的編寫,並可以進行直接的編譯和除錯。VSC目前雖然還存在不少問題,比如開啟文件的效率偏低,其整合的外掛功能相對於Windows平臺下的Visu

Linux常見的~/.bashrc/etc/profile/etc/ld.so.config小科普以及caffe編譯遇到的相關問題解決

~/.bashrc 用於非互動式模式,即nonlogin shell,在這種模式下,shell不與你進行互動,而是讀取存放在檔案中的命令,並且執行它們。當它讀到檔案的結尾,shell也就終止了。/etc/bashrc:為每一個執行bash shell的使用者

Ubuntu14.04C++程式編輯編譯執行

1、輸入組合鍵“Ctrl+Alt+t”調出終端;  安裝vim:輸入 sudo apt-get install vim;  安裝gcc:輸入 sudo apt-get install g++。 2建立目錄,建立檔案,可通過命令ls檢視 3 建立完first.cpp

Linux用戶組文件權限詳解

目錄 管理權限 權限不足 日期 查看 add 綜合案例 天然 width 在linux中的每個用戶必須屬於一個組,不能獨立於組外。在linux中每個文件有所有者、所在組、其它組的概念 - 所有者 - 所在組 - 其它組 - 改變用戶所在的組 所有者 一般為文件的創建者,

Linux的之touchmvcprm

linux touch mv cp rm touch 新建文件 touch 文件名 例如: touch file1 在當前目錄新建名為file1的文件 註意: 1)同一目錄無法創建同名的文件 2)Linux的文件名是區分大小寫的 mv 修改文件名(或者目錄的名

linux的權限特殊權限acl

權限 suid sgid acl 首先,我們都知道Linux是一個多用戶操作系統,那麽問題就來了,假設我有一個文件叫file1,這個文件是用戶user1的,user1有一個項目組g1,他希望他項目組裏的同事可以查看修改這個文件,但是不希望其他人看到文件中的內容當然也不能編輯。那怎麽解決這個問題

linuxfind查找文件後使用xargsexec進行刪除壓縮處理。

find exec xargsmtime 文件內容上次修改時間   atime 文件被讀取或訪問的時間   ctime 文件狀態變化時間   mtime 和 atime 的含義都是很容易理解的,而 ctime 則需要更多的解釋。由於 inode 維護著每個文件上的元數據,因此,如果與文件有關的元數據發生變化,

LinuxTomcat的啟動關閉

lpad ade web dir xms 僵屍 fun table linux下 在Linux系統下,啟動和關閉Tomcat使用命令操作。 進入Tomcat下的bin目錄 1 cd /java/tomcat/bin 啟動Tomcat命令

LinuxElasticSearch6.4.xElasticSearch-HeadKibana以及中文分詞器IK的安裝配置

ElasticSearch 安裝配置 下載 # 官網下載壓縮包 [[email protected] /home]#  wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.

Linuxjava獲取CPU記憶體磁碟IO網路頻寬使用率

原文地址:https://www.cnblogs.com/gisblogs/p/3985393.html 一、CPU 使用proc檔案系統,"proc檔案系統是一個偽檔案系統,它只存在記憶體當中,而不佔用外存空間。它以檔案系統的方式為訪問系統核心資料的操作提供介面。使用者和應用程式可以通過p

LinuxTomcat的安裝啟動關閉以及配置檔案的修改

安裝 前往tomcat官網https://tomcat.apache.org下載需要的版本。下面以 tomcat8 為例,下載過程如下: 設tomcat安裝包所在目錄為tomcat_download,使用如下命令解壓到資料夾中即完成安裝: tar -xvzf apache-