Linux下编辑、编译、调试命令总结 | 您所在的位置:网站首页 › 戴森吸尘器的优点和缺点 › Linux下编辑、编译、调试命令总结 |
GCC gcc是linux系统集成的编译器。在linux环境下编辑程序,首先需要克服的便是没有集成开发环境的一键式操作所带来的麻烦。这其中涉及命令行操作、编译选项的设定、文件依赖关系的书写(makefile)等问题。这里主要介绍的是关于gcc的常用命令行参数及其相应的作用。(若编译C++文件,则只需将下列命令的 gcc 换为 g++,源文件的后缀应为 .C/.cpp/.c++/.cc等) 基本格式:gcc [options] file1 file2... //若不加入参数,则按默认参数依次执行编译、汇编和链接操作,生成的可执行文件名为 a.out 常用参数:-E //只执行预处理操作,直接输出到标准输出(可通过 -o 命令指定输出到文件中 ),可配合 -v 命令使用,查看头文件的搜索目录,即使用 -E -v 编译选项 -S //只执行到编译操作完成,不进行汇编操作,生成的是汇编文件(.s 或 .asm),内容为汇编语言 -c //执行编译和汇编,但不进行链接,即只生成可重定位目标文件(.o),为二进制文件,不生成完整的可执行文件 -o filename //将操作后的内容输出到filename指定的文件中 -static //对于支持动态链接的系统,使用静态链接而不是动态链接进行链接操作 -g //编译时生成debug有关的程序信息(供gdb使用) --save-temps //生成编译过程的中间结果文件(包括预处理文件(x.ii)、汇编代码(x.s)、目标文件(x.o)和最终的可执行文件) -IPATH //在PATH指定的目录下寻找相关的include文件,参数中间不加空格 -lxx //其中xx为指定函数库,对于Linux环境下的函数库,静态库后缀为.a,动态库后缀为.so,一般库名为libxx.a或libxx.so,如加入libm.so库,则使用参数-lm(去除lib和后缀.a\so) -LPATH //在PATH指定的目录下寻找相关的库文件,即-lxx指定待链接的库,-L指定寻找该库的路径。不指定时搜索默认的库函数路径。 -std=xx //指定编译使用的语言标准,如 -std=c++11 使用 c++11 标准 -x language //指定待编译文件的语言,而不是由编译器根据文件后缀自行判断。即默认情况下gcc根据文件后缀判断使用的编程语言。例如使用文件名 hello 作为源文件名是不合适的,应使用hello.c -Wall //输出一些简单的错误以及一些可能存在问题的警告 -Wextra //输出-Wall不包含的警告等 -Werror //将警告视为错误输出 -Wl,option //通过该选项将参数 option 作为后续链接器 ld 使用的参数 -Wl,rpath=/path/to/lib //为链接器指定一个非默认的运行时库的搜索路径,运行采用了该选项编译的程序时,链接器会在-rpath 指定的目录中搜索所需的 so 库文件,以将其载入内存中 -D name=definition //加入宏定义,若不指定def,则默认为1 -O1、-O2 //规定编译器的优化等级,优化级数越高执行效率一般越好,但是优化会改变原有程序结构,使得其汇编不易理解 //一些进行缓冲区溢出实验时可能需要的选项 -fstack-protector\-fno-stack-protector //是否开启堆栈保护,这里的保护是在返回地址之前加入一个验证值来确保返回地址不被破坏 -z execstack //启用可执行栈,默认是禁用的 //(echo 0 >/proc/sys/kernel/randomize_va_space 关闭地址随机化,这是一个单独的命令,操作需要root权限)//编译动态链接库的选项 -shared -fPIC //笔者用到的编译动态链接库即 .so 库的选项,其中 -shared 表示生成一个共享目标文件(shared object),-fPIC 表示忽略 PIC(position-independent code) //对应的还有个选项 -fpic,其会生成 PIC,详细内容可参见 man gcc 上述编译使用的参数一般在直接使用 gcc / g++ 时作为命令行参数指定。如果想要在某些调用了 gcc / g++ 的编译过程中加入所需的编译参数,即无法直接通过命令行参数的方式指定编译参数时,可以通过全局变量的方式( Linux 环境下 )指定所需的编译参数。具体而言,使用 CXXFLAGS 指定 g++ 编译参数,使用 CFLAGS 指定 gcc 编译参数。 export CXXFLAGS="-std=c++11" //通过全局变量指定额外的编译参数 export CFLAGS="-std=c99"
举例说明 (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 --args 加入运行参数。 gdb --args a.out arg1 arg2gdb以命令行环境运行,进入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 |
CopyRight 2018-2019 实验室设备网 版权所有 |