程序是由多个段构成的,比如,.text是用来存放代码段的,.data是用来存放初始化好的数据的,.bss是用来存放未初始化好的数据的;
对于.rdata,其中放的是我们程序中定义的只读初始化好的数据,在程序中采用const进行修饰的变量就被存放在这一段上;
对于每一个可加载的(loadable)或是可以重新分配的(allocatable)的段,其都存在一个VMA和一个LMA,简单说来VMA指示的是段在程序运行时的开始地址,而LMA是指段的存放首地址。在大多数情况下VMA和LMA是一样的,尤其是采用boot loader的嵌入式系统。由于绝大部分的嵌入式系统都不使用虚拟内存,所以,VMA地址就是系统的实地址;
objdump -W test //查看程序中的调试信息
objdump -d test //显示程序文件的汇编代码
在使用-d选项进行反汇编时,还有一个非常有用的选项是-S,其用途是告诉objdump在反汇编时同时显示C/C++源程序和与之对应的汇编代码;
objdump -S -d test
采用将汇编与源代码相结合显示的方式,有助于我们去了解高级语言的语法从汇编语言的角度是如何实现的;
采用-f选项可以显示目标文件的头信息。其中最要注意的是start address,其指示了这一程序被执行时的入口地址是什么。
objdump -f test
对于嵌入式系统,当boot loader加载完程序后,就会跳转到start address运行被加载的程序。
另一个非常有用的选项是-s,将它与-j参数配合使用能查看某一个段中的具体内容。比如,查看test中.data段的内容:
objdump -s -j .data test
生成一个只包含.text段的目标文件,通过-j参数可以指定哪一个段使我们所需要抽取的。
objcopy -j .text test onlytext
查看结果
objdump -h onlytext
objdump -f onlytext
如果要指定多个段需要拷贝,那么可以使用多个-j参数
objcopy -j .text -j .data -j .bss test new
使用-R参数可以删除一个段,
objcopy -R .text test notext
objdump -h notext
为了减少程序文件所占用的空间,我们可以将程序中的调试信息去除,最为常用的是采用strip工具达到这一目的。但是,采用objcopy的--strip-debug选项也可以达到同样的目的。
objcopy --strip-debug notext
objdump -h notext
objcopy最为重要的功能是能按照我们的需要抽取程序文件中的段。在有的嵌入式系统中,比如制作boot loader时就会需要用到objcopy,以便将代码段抽取出来,然后使用烧写器将代码烧到系统的启动运行地址处(通常是一块flash中)。
ranlib用于在档案文件中生成文件索引,ar中的s参数具有同样的功能。当档案文件增加了索引后,对于其中文件的存取速度将更快。如果档案文件是一个静态库,那么我们在使用静态库进行连接时,其速度会有所加快。
ranlib libmy.a
用nm加上一个-s参数来查看档案文件中的索引信息,
nm -s libmy.a
总体上说,readelf工具的功能objdump都有;
size工具就是列出程序文件中各段的大小,.rdata段被归类到.text段中,而.idata段被归类到.data段中;
size test
sieze -A test
strings用于查看我们的程序文件中的可显示字符。
strings test
在C程序中使用__FILE__宏时,就会在.rdata段中生成函数名字符串。即使你用strip将程序文件中的调试信息都去掉,你仍然可以通过strings看到这些信息,因为这些信息都是存在.data段(或是.rdata)中;
strings是输出.data段中的字符串信息的;
指令是存放在.text段的,数据存放在.data和.bss段;
初始化好的变量,其被存放在.data段中,而对于没有初始化好的段其被存放在.bss段中;
.data段与.bss段的区别:
对于初始化好的全局变量,编译器将其地址分配在.data段中,当程序被boot loader加载时,则只需将位于程序文件中的.data数据复制到内存所对应的地址空间,从而一次性的完成所有需要初始化的全局变量的初始化;对于.bss段,由于其中的变量是没有初始化好的,所以不需要在程序文件中保存其内容,这样的好处是能减小程序文件的大小。而当boot loader加载程序时,会自动对被加载程序的.bss段进行清零。这就是为什么没有初始化值的非指针全局变量其初始值总为0,而对于指针其初始值则是NULL;
全局变量或是函数中的静态变量,其在程序编译完成时就决定了内存空间的分配,其所占用的内存只有当程序退出时才释放,意识到这一点非常的重要。