binutils——查看可执行文件中包含的信息

有时候我们知道我们编译出来的可执行文件中包含了什么。方便我们查找问题。但是可执行文件又不可以直接打开。

那么我们可以使用什么工具来查看可执行文件包含的信息呢?

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

  • 反汇编目标文件,查看汇编到源码的映射

    1. objdump –d func.o
    2. objdump –S func.o
  • 查看目标文件中的详细段信息

    1. 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. 执行程序

嵌入式环境
这里写图片描述

  1. 源代码交叉编译成可执行程序
  2. 可执行程序烧写到Flash
  3. 根据Flash类型判断是否需要将代码拷贝到RAM中
    a) NorFlash因为不能直接执行程序,需要将代码拷贝到RAM中执行,所以加载地址和虚存地址并不相同。
    b) 而NandFlash可以直接执行程序。那么并没有虚存地址。
  4. 执行程序

猜你喜欢

转载自blog.csdn.net/small_prince_/article/details/80670282