编译工具链

生成可执行程序的过程

按照细致的小过程来说,这个过程包含:预处理、编译、汇编、链接四个小过程。

C程序编译和链接的过程-图

预处理过程指令

编译过程指令

汇编过程指令

链接过程指令

不加任何选项,直接使用gcc指令,该指令可能激活预处理、编译、汇编和链接四个步骤。大多数情况下,我们都会选择使用该指令,一步到位。

gcc指令其它常用选项

-Wall添加警告信息:

-O0,-O1,-O2,-O3编译器优化级别:

O --Optimization

编译器的4个优化级别,-O0表示不优化,-O1为默认值,开发时常选择,-O2为生产环境下常用的优化级别,-O3的优化级别最高。

-O3的优化手段比较激进,生产环境一般不会选择。

-g添加调试信息:

g --generate debugging information

-I选项

I -Include

-I选项的作用实际上是:

改变头文件包含语法的搜索目录优先级,总是优先去搜索该选项指定的目录,搜索不到时,才按照既定的搜索的路径搜索。比如:

  1. <>方式:表示搜索头文件时,总是先去"../header"下搜索,搜索不到时,再去操作系统头文件目录中寻找。

  2. ""方式:表示搜索头文件时,总是先去"../header"下搜索,搜索不到再去当前目录"."中寻找头文件,如果还找不到再去操作系统头文件目录中寻找。

GDB调试程序

第一步:带调试信息编译代码

编译过程会去掉代码中诸如变量名这样的调试信息,从汇编代码开始这些调试信息就被替换成了内存地址。

所以要想使用GDB调试程序。首先第一步就是:使用带"-g"的指令编译生成可执行程序。

第二步:进入GDB调试界面

一个最基础的指令——查看源代码

第三步:打断点

断点信息-图

这段信息从左往右内容是:

  1. Num:断点的唯一性标识编号,一次Debug过程断点编号会从1开始,且不会重置一直累加。

  2. Type:断点的类型,这里显示"breakpoint",表示断点都只是普通断点。

  3. Disp(Disposition,性格):它表示断点触发后,是否会继续触发。

    1. keep就表示它是一个持久的断点,只要不删除就一直存在,每次启动都会触发。

    2. 这个值如果是del就表示,该断点是一个一次性断点。

  4. Enb(enable):指示断点是否生效,可以通过dis指令设置该属性。

  5. What:指示断点在源代码的哪个位置

GDB常用调试指令

逐语句/单步调试

跳出并执行完函数

逐过程

监视窗口/查看变量取值

如果想要持续的,展示某个表达式的值,使用格式如下:

如果需要查看所有局部变量的值,局部变量窗口,使用格式如下:

继续,跳过一次断点:

忽略断点n次

查看堆栈信息

查看内存,内存窗口

x --examine

内存数据的输出格式有:

  1. o(octal),八进制整数

  2. x(hex),十六进制整数

  3. d(decimal),十进制整数

  4. u(unsigned decimal),无符号整数

  5. t(binary),二进制整数

  6. f(float),浮点数

  7. c(char),字符

  8. a(address),地址值

  9. c(character):字符

  10. s(string),字符串

一个内存单元的大小的表示,有以下格式:

  1. b(byte),一个字节

  2. h(halfword, 2 bytes),二个字节

  3. w(word, 4 bytes),四个字节

  4. g(giant, 8 bytes),八个字节

输入命令行参数

当main函数的形参列表是int argc, char *argv[]时,允许可执行程序传参命令行参数。如果想要使用GDB调试带命令行参数的可执行程序,有以下两种方式可以选择:

  1. 在启动GDB时,使用指令gdb --args ./a.out arg1 arg2 arg3...即可表示传递命令行参数,其中a.out表示可执行程序的名字。

  2. 如果已经启动了GDB,可以使用以下两种方式都可以传递命令行参数:

    1. 使用指令set args arg1 arg2....,其中指令部分是set args,后面的部分则是参数。

    2. 使用指令run/r arg1 arg2启动,也表示传递命令行参数。

利用display,持续显示数组特定范围的取值:

观察断点:

调试Coredump文件

Coredump 文件常用于辅助分析和 Debug,下面介绍一下这种调试手段。

ulimit --user limit

默认情况下,该指令输出的第一行就是:

core file size (blocks, -c) 0

表示此时系统允许生成的core文件最大是0个字节,即不允许生成。

所以我们需要用下列指令将core文件的大小设置为不受限制:

默认情况下,上述操作后可能还是无法生成Core文件,可以切换到root用户或者使用sudo权限,然后补充一下core文件的配置信息到目标文件里。

具体的操作如下,先打开配置文件:

将下列信息补充到配置文件末尾(注意前面不要加#号)

紧跟着还需要执行以下指令让配置信息生效:

这段配置信息的目的是给core文件设定一个固定的格式,这样设置后,再次执行报错可执行程序就会生成core文件了。

但是要注意:一般只有段错误才会生成对应core文件,像上面数组越界引发未定义行为是没有段错误的,也就不会生成core文件。

然后就可以用指令:

查看报错的一些信息,此时再利用bt等指令就可以进行正常的程序调试了。