Li Jiaheng's blog
1028 字
5 分钟
编译与调试 - GCC and GBD

GCC#

编译程序的过程:
file.c ---> (预处理器cpp处理,将宏定义和声明中的文件等直接嵌入到file中去) file.i ---> (编译器ccl处理,生成机器代码,一种汇编语言) file.s 汇编程序(文本) --->(汇编器as处理,生成可重定位目标程序) file.o (二进制) --->(链接器ld处理,加入特殊函数如i/o等,生成可执行目标程序) file

利用gcc的命令可以在其中任何一步将其打断。#

参数效果
-Og -O1 -O2-Og不优化,按源代码生成机器代码,后者优化
-E只进行预处理
-S只生成汇编程序文本.s,此时可以查看汇编代码
-c只生成.o二进制文件,无法查看
-o生成可执行目标程序,一定要有main()
-std=选择使用不同标准
filename(末)可同时编译一组文件,有且仅有一个main()

生成静态库,链接可重定位目标模块与静态库#

1、形成静态库:AR工具。将1.o 2.o 3.o...组织为静态库name.a:  
ar rcs name.a 1.o 2.o 3.o  
生成的name.a在同一个目录下。  
2、进行手动链接:gcc  
gcc -static -o name_executable 1.o 2.o ./my_lib.a  
可见最后的静态库文件必须以路径的形式给出。  

将源文件生成共享库,编译时动态链接#

生成共享库:  
gcc -shared -o -fpic libXXX.so src1.c src2.c src3.c ...  
告诉GCC要生成要适应动态解析引用的可执行目标文件:  
gcc -o prog main.c ./libXXX.so  
只要包含这个动态库的文件路径就行  

应用中(running time)有动态链接,需这样编译#

gcc -rdynamic -o prog main.c -ldl  

编译时打桩#

gcc -DCOMPILETIME -c mymalloc.c  //包装函数所在  
gcc -I. -o main main.c mymalloc.o  

链接时打桩#

gcc -DLINKTIME -c mymalloc.c  
gcc -c main.c  
gcc -W1 --wrap,malloc -W1 --wrap,free -o main main.o mymalloc.o  

运行时打桩#

gcc -DRUNTIME -shared -fpic -o -mymalloc.so mymalloc.c -ldl  
gcc -o main main.c  
运行打桩后的main:  
LD_PRELOAD="./mymalloc.so" ./main  

GBD#

硬查看.o文件#

(gbd)x/<num>xb function_name  

其中,第一个x是gbd的简写。num表示表示一个数字,表示从函数function_name或者其它内存组件的地址开始,往后输出num个十六进制格式(x)的字节(b)

GBD语法#

和普通调试类似,也是断点、执行。。。当时GBD可以以任何形式读任何内存地址的值,读寄存器信息、栈帧信息,反汇编等等。
是对可执行目标文件的进行调试,对应的是机器代码,所以很难追踪变量,使用它调试会有难度。
启动GBD:

>> gbd prog  

1)开始和停止

>> quit 退出  
>> run  运行程序,并在后面给出命令行参数  
>> kill 停止程序  

2)断点

>> break function_name  在函数...入口处设置断点  
>> break * addr      在地址addr处设置断点(提前反汇编获取机器代码)  
>> delete n        删除断点m  
>> delete         删除所有断点  

3)执行

>> stepi  执行一条(机器)指令  
>> stepi n  执行n条指令  
>> nexti  以函数为单位,执行一个函数  
>> continue  继续执行(到下一个断点)  
>> finish  运行到当前函数返回  

4)检查代码、反汇编

>> disas  反汇编当前函数  
>> disas function_name  反汇编函数...  
>> disas addr  反汇编addr附近的函数  
>> disas addr1 addr2 反汇编指定范围内的所有代码  
>> print /x $rip  以十六进制输出程序计数器值  

5)检查数据

>> print <type> $XXX  以某个进制形式输出寄存器XXX的值。<type>缺省为十进制,/x为十六进制,/t为二进制。  
>> print * (type *) addr  输出位于地址addr处的type类型的数  

6)其它

>> info frame  当前栈帧信息  
>> info registers  所有寄存器的值  
>> help  

GBD的图形化扩展 :DDD

反汇编#

使用

objdump -d filename  

可以直接在命令行中输出反汇编结果。对二进制文件.o,和可执行目标文件都可以反汇编。生成的反汇编结果中机器指令的表示会和.s中的微妙地有些不同。
当然也有专门的反汇编程序。

编译与调试 - GCC and GBD
https://namisntimpot.github.io/posts/computersystem/basis/gcc-and-gbd/
作者
Li Jiaheng
发布于
2022-08-15
许可协议
CC BY-NC-SA 4.0