学习交流加linux
- 我的qq: 1126137994
- 我的微信: liu1126137994
- 学习交流资源分享qq群: 962535112
上一篇文章咱们学习了gcc编译器的相关内容。点击查看上一篇文章:gcc编译器。本篇文章接着上一篇文章,学习GNU为GCC提供的辅助开发工具集Binutils。Binutils工具集,主要是用于在代码调试的时候,定位bug的一些手段。咱们主要学习如下几个工具的使用: 微信
本篇文章先学习使用addr2line与strip工具。函数
首先咱们要知道,gcc编译程序的时候,加上-g
选项,表示在目标文件中生成调试信息。几乎全部调试辅助工具,都依赖于程序的调试信息。工具
addr2line工具。顾名思义,能够将地址转换为行号。它经常使用于分析定位内存访问错误的问题。以实际例子为例:学习
test.c程序开发工具
#include <stdio.h>
int g_global = 0;
int g_test = 1;
extern int* g_pointer;
extern void func();
int main(int argc, char *argv[]) {
printf("&g_global = %p\n", &g_global);
printf("&g_test = %p\n", &g_test);
printf("&g_pointer = %p\n", &g_pointer);
printf("g_pointer = %p\n", g_pointer);
printf("&func = %p\n", &func);
printf("&main = %p\n", &main);
func();
return 0;
}
复制代码
func.c程序ui
#include <stdio.h>
int* g_pointer;
void func() {
*g_pointer = (int)"D.T.Software";
return;
}
复制代码
咱们在linux下编译如下程序(注意我使用gcc-4.4.5版本编译没有警告显示。可是使用较高版本的gcc编译器,可能会有警告。这里咱们忽略警告):spa
运行程序.net
显示结果为: debug
其实结果也在乎料之中。咱们分析程序很容易知道,func函数中 *g_pointer = (int)"D.T.Software";
这句话,使得在0地址赋值了。由于int* g_pointer;
只是定义了g_pointer
却没有赋值,那么g_pointer
实际上一开始是指向0地址,后面又对它进行赋值。至关于对0地址进行操做。
可是咱们知道0地址,是不能被操做的。因此会产生段错误。这个程序很短,问题咱们很容易发现。可是若是这个歌程序有一千行,一万行的话,那么问题就很难定位到。此时addr2line工具就可以上场。
下面来讲明如何使用addr2line工具。
首先开启core dump选项。使用命令ulimit -c unlimited
。开启这个选项后,在运行可执行程序的时候,会将程序崩溃前最后一刻的内存状态信息,转储(保存)到一个core文件。这个文件叫作核心转储文件。咱们能够经过读取该文件,获取一些用于调试的信息。
开启core dump选项后,再次运行可执行程序,来生成core文件。
咱们能够看到,段错误后面显示核心已转储。此时查看当前目录的话,就能够看到core文件。
dmesg core
命令读取core文件的内容,显示内容最后部分以下:能够看到,最后一刻IP寄存器的值为0x080483d1
.出问题的代码就在这个地址处。可是咱们没法知道这个地址处究竟是个啥。可是能够利用addr2line工具,将这个地址转换为代码中对应的行号。
addr2line 0x080483d1 -f -e lyy
很明显,已经找打缘由,是func.c程序的第7行。当从两万行大代码中找到这个错误,也是很激动的!!!
实际上,addr2line可以正常工做,必须依赖于程序的调试信息。而咱们在编译程序的时候,也确实让程序生成了调试信息。如上编译的时候带的-g
选项。
当可执行程序里面带有大量的调试信息,会致使可执行程序,很是的大。若是在大型的软件中,软件在发布以前,确定是要将这些调试信息去掉,好让发布出去的程序占用内存空间更小,否则程序太大,对用户来讲也是很是不友好的。
其实这就是所谓的release版本的程序。在发布以前,还须要调试的程序,咱们称为debug版本程序。
那么如何剔除调试信息?使用strip工具!以下图是release版本的程序大小为9074:
使用strip将调试信息剔除后大小为5512:
结果显而易见!!!
还有其余工具,放在下一篇文章学习!!!