嵌入式系统及应用Linux学习笔记(三)— GCC/G++编译器与调试器
Linux GCC/G++编译器与调试器
Linux GCC/G++编译器与调试器
GCC/G++编译器
- 目前Linux下最常用的C语言编译器是GCC(GNU Compiler Collection),它是Linux平台编译器的事实标准。
- GCC是GNU项目中符合ANSI C标准的编译系统,能够编译用C、C++和Object C等语言编写的程序。
- GCC之所以被广泛采用,还因为它能支持各种不同的目标体系结构。它既支持基于宿主的开发,也支持交叉编译。
- 目前,GCC支持的体系结构有四十余种,常见的有X86系列、ARM、PowerPC等。同时,GCC还能运行在不同的操作系统上,如Linux、Solaris、Windows等。
- 开发者通常选择GCC来编译C语言编写的源代码,选择G++来编译C++源代码。
GCC简介
使用GCC编译程序时,编译过程可以被细分为四个阶段:
- (1)预处理(Pre-Processing)
- (2)编译(Compiling)
- (3)汇编(Assembling)
- (4)链接(Linking)
在这四个阶段中可以设置选项分别生成扩展名分别为“.i”、“.s”、“.o”的文件,以及最终可执行文件,各扩展名文件含义如下:
-
.c
:最初的c源代码文件。 -
.i
:经过编译预处理的源代码。 -
.s
:汇编处理后的汇编代码。 -
.o
:编译后的目标文件,含有最终编译出的机器码,但它里面所引用的其他文件中函数的内存位置尚未定义
下面以程序hello.c为例具体看一下GCC是如何完成以上四个步骤的,程序hello.c源代码如下所示。
#include<stdio.h>
int main(void)
{
printf("Hello World!/n");
return 0;
}
(1)预处理阶段
- 在该阶段,编译器将上述代码中的stdio.h编译进来。GCC首先调用cpp进行预处理,根据以字符#开头的命令修改原始的C程序。
- 如hello.c中的指令#include
<stdio.h>告诉预处理器读系统头文件stdio.h的内容,并把它直接插入到程序文本中去,结果就得到经过编译预处理的源代码hello.i。
(2)编译阶段
- GCC调用ccl检查代码的规范性,是否有语法错误等,以确定代码实际要做的工作,在检查无误后,把代码翻译成汇编语言,生成汇编处理后的汇编代码hello.s。这个阶段对应的GCC命令如下所示。
$gcc -S hello.i -o hello.s
(3)汇编阶段
- GCC调用as把编译阶段生成的hello.s文件转成编译后的目标文件hello.o,但hello.c中所引用的其他文件中函数(如printf)的内存位置尚未定义。这个阶段对应的GCC命令如下所示:
$gcc -c hello.s -o hello.o
(4)链接阶段
- GCC调用ld将程序的目标文件与所需的所有附加的目标文件连接起来,最终生成可执行文件。如GCC找到hello.c所调用的函数printf函数库所在位置/user/lib,把函数的实现链接进来,生成最终的可执行文件hello,可以利用下面的命令完成。
$gcc hello.o -o hello
GCC的使用
格式:gcc [选项|文件]…
(1)总体选项
(2)链接选项
(3)警告选项
示例:
(1)编译当前目录下的文件helloworld.c。
$gcc helloworld.c
该命令将helloworld.c文件预处理、汇编、编译并链接形成可执行文件。这里未指定输出文件,默认输出为a.out,a.out为可执行程序文件名。
(2)将当前目录下的文件helloworld.c编译成名为helloworld的可执行文件。
$gcc –o helloworld helloworld.c
(3)将当前目录下的文件helloworld.c编译为汇编语言文件。
$gcc –S helloworld.c
该命令生成helloworld.c的汇编文件helloworld.s,使用的是AT&T汇编。
(4)将文件testfun.c 和文件test.c 编译成目标文件test
方法1:
$gcc testfun.c test.c -o test
方法2:
$gcc -c testfun.c //将testfun.c编译成testfun.o
$gcc -c test.c //将test.c编译成test.o
$gcc testfun.o test.o -o test //将testfun.o和test.o链接成test
(5)编译当前目录下的程序bad.c,同时查看编译过程中所有报警信息。
程序bad.c的源码如下所示。
#include <stdio.h>
int main (void)
{
printf ("Two plus two is %f\n", 4);
return 0;
}
程序调试工具gdb
gdb是Linux系统中一个功能强大的GNU调试程序,它可以调试C和C++程序,使程序开发者在程序运行时观察程序的内部结构和内存的使用情况。gdb提供如下功能:
- (1)运行程序,设置所有的能影响程序运行的参数和环境。
- (2)控制程序在指定的条件下停止运行。
- (3)当程序停止时,可以检查程序的状态。
- (4)修改程序的错误,并重新运行程序。
- (5)动态监视程序中变量的值。
- (6)可以单步逐行执行代码,观察程序的运行状态。
- (7)分析崩溃程序产生的core文件。
1.启动gdb
要使用gdb调试程序,首先在编译时,必须把调试信息加到可执行文件中,可通过使用编译器gcc的 -g 参数完成。
如:$gcc -g hello.c -o hello
GDB常用调试命令
启动gdb的方法有以下四种:
(1)gdb
(2)gdb <program>
(3)gdb <program> core
gdb同时调试可执行程序program和文件core,文件core是程序崩溃时产生的文件,仅仅是一个内存映象(加上调试信息),主要是用来调试的。
(4)gdb <program> <PID>
PID是程序运行时的进程号,gdb会自动绑定到该进程上,并调试。
显示调试程序的源代码
gdb可以用list(list指令可简写为l)命令来显示程序的源代码,其方法有如下几种:
(1)格式:list [file:]linenum
说明:显示程序file中的第linenum行周围的源代码。
(2)格式:list [file:]function
说明:显示程序file中的函数名为function的函数的源代码。
(3)格式:list
说明:显示当前行后面的源代码。
(4)格式:list –
说明:显示当前行前面的源代码。
(5)格式:list start,end
说明:显示从行号start到end之间的代码行。默认情况下,list命令显示10行代码。
监视及更改变量值
gdb可用print (print 指令可简写为 p)命令来监视及更改变量值。
格式:
- print exp
说明:显示或改变表达式exp的值,exp是符合所用编程语言语法规则的表达式,如调试c语言编写的程序,则exp符合c语言的语法规则。
示例:
(1)显示变量a的内容。(gdb) print a
(2)显示变量a的长度。(gdb) print sizeof(a)
(3)将变量a的值设定为 10。(gdb) print (a=10)
控制程序的执行
调试程序过程中,经常需要暂停程序的运行,以便查看某些变量值的变化,及程序运行的流程。gdb可以方便地暂停程序的运行,常用的有以下几种暂停方式:断点(BreakPoint)、观察点(WatchPoint)、捕捉点(CatchPoint)。如要恢复程序运行,可以使用c命令或是continue命令。
设置和显示断点(BreakPoint)
gdb用break命令来设置断点,设置断点的方法有如下几种:
(1)格式:break <function>
说明:将程序在进入指定函数function时停住,function为函数名。
(2)格式:break <linenum>
说明:将程序在指定行号linenum停住,linenum为行号。
(3)格式:break +offset
或break -offset
说明:将程序在当前行号的前面或后面的offset行停住,offiset为自然数。
(4)格式:break filename:linenum
说明:将程序在源文件filename的行号linenum处停住,filename为源文件名,linenum 为行号。
(5)格式:break filename:function
说明:将程序在源文件filename的function函数的入口处停住,filename为源文件名,function为函数名。
(6)格式:break *address
说明:将程序在运行的内存地址address处停住,address为程序运行的内存地址。
(7)格式:break
说明:将程序在下一条指令处停住。
(8)格式:break ... if <condition>
说明:将程序在条件condition成立停住,…表示上述的参数。
(9)格式:info breakpoints
说明:显示程序设置的所有断点。
设置和显示观察点(WatchPoint)
观察点一般来观察某个表达式(变量也是一种表达式)的值是否有变化,如果有变化,马上停住程序。设置观察点的方法有以下几种:
(1)格式:watch <expr>
说明:为表达式expr设置一个观察点,当表达式的值有变化时,停住程序。
( 2)格式:rwatch <expr>
说明:为表达式expr设置一个观察点,当表达式的值被读时,停住程序。
(3)格式:awatch <expr>
说明:为表达式expr设置一个观察点,当表达式的值被读或被写时,停住程序。
可使用info命令显示程序中设置了哪些观察点,命令如下所示。
格式:info watchpoints
说明:显示程序设置的所有观察点。
设置捕捉点(CatchPoint)
在程序运行过程中,当发生了某些事件,如动态链接库加载、暂停程序运行等,可设置捕捉点来捕捉这些事件,暂停程序运行。用户可对事件作出分析判断,并采取相应措施。设置捕捉点命令如下所示。
格式:catch <event>
说明:将程序在事件event发生时停住
维护停止点
在gdb中,可以使用delete、clear、disable、enable这几个命令进行维护。
(1)格式:clear
说明:清除所有的已定义的停止点。
(2)格式:clear <function>
或clear <filename:function>
说明:清除所有设置在函数function上的停止点,或清除所有设置在源文件filename中函数function上的停止点。
(3)格式:clear <linenum>
或clear <filename:linenum>
说明:清除所有设置在指定行linenum上的停止点,或清除所有设置在源文件filename中指定行linenum上的停止点。
linenum为行号,filename为源文件名。
(4)格式:delete [breakpoints] [range...]
说明:删除指定的断点。breakpoints为断点号,如果不指定断点号,表示删除所有的断点
(5)格式:disable [breakpoints] [range...]
说明:停用指定的断点。breakpoints为断点号,如果不指定断点号,表示停用所有的断点。停用的断点,gdb不会删除,需要时利用enable命令**即可,简写命令是dis。
(6)格式:enable [breakpoints] [range...]
说明:**指定的断点,breakpoints为断点号,如果不指定断点号,表示**所有的断点。range 表示断点号的范围
为停止点设定运行命令
使用gdb提供的command命令可设置停止点的运行命令。
格式:
commands [bnum] ... command-list ... end
说明:为断点号bnum指写一个命令列表command-list,当程序停在该断点时,gdb会依次运行命令列表中的命令。bnum为断点号,command-list为执行的命令列表。
程序运行和单步调试
设置好停止点后,就可以使用run命令运行程序。
格式:(gdb) run
说明:该命令表示从程序开头执行程序,直到遇到断点或是程序执行完毕为止。
程序被停住,可用continue命令恢复程序的运行直到程序结束,或下一个断点到来。
(1)格式:
continue [ignore-count]
c [ignore-count]
fg [ignore-count]
说明:continue,c,fg三个命令功能基本相同。恢复程序运行,直到程序结束,或是下一个断点到来。ignore-count表示忽略其后的断点次数。
(2)格式:step <count>
说明:单步跟踪,count表示执行后面的count条指令后再停住,省略表示一条条执行。如果有函数调用,会进入该函数。进入函数的前提是,此函数被编译有debug信息。
(3)格式:next <count>
说明:单步跟踪,count表示执行后面的count条指令后再停住,省略表示一条条执行。如果有函数调用,不会进入该函数。
(4)格式:set step-mode
或set step-mode on
说明:打开step-mode模式,进行单步跟踪时,程序不会因为没有debug信息而不停住。
(5)格式:set step-mod off
说明:关闭step-mode模式。
(6)格式:finish
说明:运行程序,直到当前函数完成返回。打印函数返回时的堆栈地址和返回值及参数值等信息。
(7)格式:until 或 u
说明:运行程序直到退出循环体,即取消在一个循环体内单步跟踪。
(8)格式:stepi
或 si
nexti
或 ni
说明:单步跟踪一条机器指令i,一条程序代码有可能由数条机器指令完成,step i和nexti可以单步执行机器指令。
打开可执行文件后,可根据需要在程序中加入断点或观察点,并运行程序。以helloworld程序为例,可在为变量赋值前加入断点,并运行程序。方法如下:
(gdb) break 5 // 在源代码第5行,即变量c赋值处加入断点
(gdb) run // 运行程序
上一篇: Hadoop2.7.3分布式安装
下一篇: 有理想的程序员必须知道的15件事