有时候我们知道我们编译出来的可执行文件中包含了什么。方便我们查找问题。但是可执行文件又不可以直接打开。
那么我们可以使用什么工具来查看可执行文件包含的信息呢?
nm
- 列出目标文件中的标识符(变量名,函数名)
- 输出结果由三部分组成:{ 地址, 段, 标识符 }
操作示例:
root@Shaw-vm:/home/delphi/workspace# nm test.out
08049f28 d _DYNAMIC
08049ff4 d _GLOBAL_OFFSET_TABLE_
080484bc R _IO_stdin_used
w _Jv_RegisterClasses
08049f18 d __CTOR_END__
08049f14 d __CTOR_LIST__
08049f20 D __DTOR_END__
08049f1c d __DTOR_LIST__
080484cc r __FRAME_END__
08049f24 d __JCR_END__
08049f24 d __JCR_LIST__
0804a014 A __bss_start
0804a00c D __data_start
08048470 t __do_global_ctors_aux
08048340 t __do_global_dtors_aux
0804a010 D __dso_handle
w __gmon_start__
0804846a T __i686.get_pc_thunk.bx
08049f14 d __init_array_end
08049f14 d __init_array_start
08048400 T __libc_csu_fini
08048410 T __libc_csu_init
U __libc_start_main@@GLIBC_2.0
0804a014 A _edata
0804a01c A _end
0804849c T _fini
080484b8 R _fp_hw
08048294 T _init
08048310 T _start
0804a014 b completed.7065
0804a00c W data_start
0804a018 b dtor_idx.7067
080483a0 t frame_dummy
080483c4 T func
080483d6 T main
U printf@@GLIBC_2.0
段标识符说明:
size
- 获取目标文件中的所有段大小
- size test.out
在一些资源受限的嵌入式设备中,我们可以通过size命令,查看目标文件各个段的大小。根据各个段的大小进行对内存的合理分配。
操作过程:
root@Shaw-vm:/home/delphi/workspace# size test.out
text data bss dec hex filename
909 256 8 1173 495 test.out
strings
- 获取目标文件中的所有字符串常量
- strings test.out
我们可以通过打印目标文件中的字符串,可以判断有没有字符串是冗余的,如果程序中存在版本信息的字符串,也可以通过strings获得程序的版本信息。
操作过程
root@Shaw-vm:/home/delphi/workspace# strings test.out
/lib/ld-linux.so.2
__gmon_start__
libc.so.6
_IO_stdin_used
printf
__libc_start_main
GLIBC_2.0
PTRh
[^_]
Hello world
objdump
反汇编目标文件,查看汇编到源码的映射
- objdump –d func.o
- objdump –S func.o
查看目标文件中的详细段信息
- objdump –h test.out
操作示例:
root@Shaw-vm:/home/delphi/workspace# objdump -h test.out
test.out: file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .interp 00000013 08048134 08048134 00000134 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
1 .note.ABI-tag 00000020 08048148 08048148 00000148 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
2 .note.gnu.build-id 00000024 08048168 08048168 00000168 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
3 .gnu.hash 00000020 0804818c 0804818c 0000018c 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .dynsym 00000050 080481ac 080481ac 000001ac 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
5 .dynstr 0000004c 080481fc 080481fc 000001fc 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
6 .gnu.version 0000000a 08048248 08048248 00000248 2**1
问题:这些标识符代表了什么意思?在实际工作中其什么作用?
objdump–h 的输出说明
看到输出说明,我们对VMA、LMA、File off这三个名词并不熟悉。而这三个名词在程序的运行起到什么作用呢?我们需要分情况来讨论这个问题。
桌面环境
1. 操作系统分配虚拟内存空间给可执行文件
2. 将可执行文件中的段拷贝到虚存空间当中
a) 如何准确讲各个段拷贝到虚存空间?
b) 拷贝到虚存空间的哪个地址?
实际上,程序编译完成时会产生一个虚地址,而这个虚地址就是我们要加载到虚存空间的目标地址。
当加载程序时,通过“File off”信息,从文件中读出相应段的内容,然后将这一内容写到段所指定的VMA处。
此时VMA = LMA。
3. 执行程序
嵌入式环境
- 源代码交叉编译成可执行程序
- 可执行程序烧写到Flash
- 根据Flash类型判断是否需要将代码拷贝到RAM中
a) NorFlash因为不能直接执行程序,需要将代码拷贝到RAM中执行,所以加载地址和虚存地址并不相同。
b) 而NandFlash可以直接执行程序。那么并没有虚存地址。 - 执行程序