开发环境:
工具集:
这些工具集是为了配合GCC编译器进行高效开发而设计的。
实验:
test.c:
func.c:
g_pointer默认为空指针。
使用addr2line定位错误:
开启core dump选项就是为了记录程序崩溃的最后一刻程序的状态和寄存器的状态。
成功定位到了出错的地方。
剔除调试信息:
示例:
剔除调试信息后程序变小了,但是这时候没有了调试信息,也就不能有addr2line定位bug了:
ar:
将x.o y.o打包进libname.a中。
ar的x选项可以将.a解压。
实验:
在链接是有时候我们不想链接.a文件中的所有内容,这时候我们就可以将.a解压出来,找出需要的.o文件,然后链接那个.o就可以了。
nm:
实验:
使用nm查看符号:
func前面的T代表代码段,00000000表示func的地址相对于代码段的起始偏移。
g_pointer前面的C代表不知道这个变量位于哪个段,前面的00000004表示g_pointer的大小。
g_global在bss段,且相对于bss段的起始偏移为00000000。
g_test在data段,且相对于data段的起始偏移为00000000。
链接生成可执行文件,再次nm查看:
运行输出的结果:
运行结果和nm查看的结果相同。
objdump:
objdump -d可以得到目标文件对应的汇编代码。
示例:
objdump -S可以查看汇编到源程序之间的映射:
*g_pointer那一行对应的汇编就是它下面的那三行汇编。
objdump -h可以查看目标文件中的详细的段信息。
objdump -h输出表格的列说明:
对可执行文件执行objdump -h:
VMA和LMA是一样的。
LMA指的是什么呢?
可执行程序的加载:
在桌面环境下,加载程序的过程如下:
1、创建进程,分配虚存空间
2、将可执行文件中的段拷贝到内存中,拷贝时需要用到可执行文件中的段的信息,这些信息就在文件里面。file off表示相应的段在文件中的偏移。
根据段的VMA拷贝到虚拟内存相应的VMA地址上。编译的时候会给出每个段的虚拟起始地址VMA。这个虚地址就代表了加载的目标地址。
桌面环境中VMA等于LMA。LMA就是加载地址,指的是终点。
运行地址指的是实地址。
嵌入式环境nand:
nandflash只能存储,不能执行程序。
上电时文件系统不存在,需要从一个固定的地址读取到ram中。
这个地址叫做加载地址,这个地址在这里指的是起点。
这时VMA就不等于LMA,LMA指的是段在flash中的地址,是起始地址。
运行地址是代码在ram中执行的地址,是实地址。
嵌入式环境NOR:
nor flash可以直接执行程序。
可执行文件烧写到nor中,上电后直接在nor执行。
这时的加载地址和运行地址都是nor中的地址,这时加载地址就是运行地址,这种情况下可能没有虚存地址。
其他工具:
演示:
size查看各个段的大小,可以有目的的对每个段进行优化。
参考:狄泰软件学院视频教程