千家信息网

开发中的辅助工具(六)

发表于:2024-11-11 作者:千家信息网编辑
千家信息网最后更新 2024年11月11日,今天我们来看一看开发中的辅助工具,那么什么是开发环境呢?在我们的印象中,开发环境就指的是编写代码的环境。其实不然,开发环境包括三大部分:构建环境、调试环境以及测试环境。构建环境便指得是代码编写、程序编
千家信息网最后更新 2024年11月11日开发中的辅助工具(六)

今天我们来看一看开发中的辅助工具,那么什么是开发环境呢?在我们的印象中,开发环境就指的是编写代码的环境。其实不然,开发环境包括三大部分:构建环境、调试环境以及测试环境。构建环境便指得是代码编写、程序编译以及版本控制等;调试环境则指的是用于定位问题的辅助工具集;测试环境指的是用于验证目标程序是否满足用户的显性需求和隐形需求。显性需求指的是客户的要求,而隐形需求则指的是一些用户没有要求到的但是必须具备的要求。比如一个应用程序在 win7 系统上可以运行起来,在 win10 系统上也要能运行起来。

在嵌入式的开发中,我们在整个项目中的代码编写及目标构建上一般只花费 20% 的时间,剩下的 80% 的时间适用于测试、调试以及 bug 修复的。那么我们该如何提高开发效率呢?工欲善其事必先利其器,我们可以借助于一些工具,从而提高开发的效率。GNU 为 GCC 编译器提供了配套的辅助工具集(Binutils),网址是 http://www.gnu.org/software/binutils/ ;其中的一些工具介绍如下

工具名
功能简介
add2line
将代码地址转换为对应的程序引导
strip
提出可执行程序中的调试信息
ar
将目标文件打包成为静态库
nm
列出目标文件中的符号及对应地址
objdump
查看程序段信息及反汇编
size
查看目标文件中的段大小
strings
查看目标文件中的字符串

下来我们来一一的介绍下这几个工具。

1、addr2line : 将制定复制转换为对应的文件名和行号,常用于分析和定位内存访问错误的问题。来个示例代码进行分析说明


func.c 源码

#include int* g_pointer;int main(){    *g_pointer = (int)"D.T.Software";        return 0;}


test.c 源码

#include 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;}

我们先来分析下这份代码。我们在前面直接定义 int 类型的指针,但是并没有将其指为 NULL。那么此时 g_pointer 已经指向了内存的 0 地址处,在 main 函数中操作 0 地址处,这肯定会引起段错误。我们来看看编译运行结果

我们看到 g_pointer 是个空指针,后面就直接发生段错误,如果这是个很大的项目,几十万行的代码,相信我们定位问题就很困难了。那么此时我们该如何定位问题呢?addr2line 工具便出场了。使用的步骤如下:1、开启 core dump 选项:ulimit -c unlimited;2、运行程序,并生产崩溃时的 core 文件,执行导致程序崩溃的测试用例;3、读取 core 文件,获取 IP 寄存器的值:dmesg core;4、使用 add2line 定位代码行:addr2line 地址 -f -e test.out。如下

我们看到此时已经生成了 core 文件,我们来 dmesg core 看看 IP 寄存器的值是什么

我们看到 IP 寄存器的值是 0x080484b8,然后利用 addr2line 工具就可以直接定位到问题的所在了。

2、strip:用于剔除程序文件中的调试信息,减少目标程序的大小。一般在程序发布前都需要将调试信息剔除,过多的调试信息可能影响程序的执行效率。我们来看看它的用法,strip test.out

我们看到在经过剔除之后,它的文件大小几乎减少了一半。使用它的注意事项:1、几乎所有的调试工具都依赖于目标文件中的调试信息,调试信息的运用能够快速定位问题;2、使用 gcc 编译程序时使用 -g 选项生成调试信息,发布程序时再考虑是否使用 strip 剔除调试信息。那么这时如果想要利用 core 文件定位问题就不可以了,因为 core 文件只能定位出调试版本的信息

我们看到它是定位不出问题的所在的。

3、ar : 打包目标文件,ar crs libname.a x.o y.o;解压目标文件,ar x libname.a。下来看看是如何使用的

我们利用打包和解压命令从而就可以直接给别人发第三方库文件。如果我们只有第三方的库文件而想使用其中的一个 .o 文件,那么就可以使用解压命令来进行使用其中的一个文件。

4、nm:用于列出目标文件中的标识符(变量名、函数名),输出结果由三部分组成{地址、段以及标识符}。示例如下

段标识说明如下

我们来看看 func.o 和 test.o 文件中的标识符

我们看到在 func.o 文件中 func 是位于代码段的,它的偏移量为0。在这没有经过链接,所以显示的都是相对地址。g_pointer 属于未定义的标识符,相对偏移量为 4。下来我们看看链接后的地址

我们看到经过链接后的地址是绝对地址。

5、objdump : 反汇编目标问阿金,查看汇编到源码的映射。objdump -d func.o 或者 objdump -S func.o。查看目标文件中的详细段信息,objdump -h test.out。

objdump -h 的输出说明如下

使用输出信息如下

我们再来看看链接后的 test.out 的详细信息。

我们看到它的 VMA 和 LMA 是一样的,也就是说,虚存地址和加载地址是一样的。在进行运行程序的时候,首先是为可执行文件分配虚存,接着通过 file off 获取到相对位置,通过复制段信息过去,加载目标地址到虚存上。最后是执行程序。

6、size 用来获取目标文件中的所有段大小,size test.outstrings 用来获取目标文件中的所有字符串常量。如下

那么我们获取它们的大小和字符串有什么意义呢?在嵌入式的开发中,资源往往是非常受限的,因此我们就必须得严格控制目标文件的大小,以防止超出其界限造成不可预料的错误;我们如果想要获取某些特定的字符串时就不必去看代码了,直接用 strings 就可以看到全部的字符串了,以提高开发效率。

文件 目标 程序 信息 地址 代码 环境 定位 开发 工具 问题 大小 字符 字符串 标识 运行 效率 标识符 链接 错误 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 软件开发项目人数图 营业范围 互联网科技 小类 企业培训软件开发怎么样 软件开发行业的招标网站 软件开发雅x湖南岚鸿 服务器打开本地磁盘命令 有网为什么显示连接服务器失败 什么软件租服务器 渭南市第六届国家网络安全宣传周 数据库的链表主要介绍 饥荒服务器全自动管理工具 达梦数据库运行环境要求 建车辆管理系统数据库语言 大连网络技术服务信息中心 mongo数据库监控脚本 手机淘宝数据库系统软件 别人的网页链接自己的数据库 安全审计登录服务器 创办软件开发企业的原因 数据库操作日志能改吗 保护数据库安全的方法有哪些 基于架构的组件化软件开发 网络安全密码系统 时钟服务器 连云港固态硬盘服务器 三菱服务器编程软件下载 国际网络安全大赛最高奖金 数据库中基数是指 嵩县软件开发怎么选 山西百旺税控服务器管理系统
0