OBJ文件格式分析工具: objdump, nm,ar
首先简要阐述关于gcc、glibc和 binutils模块之间的关系
一、关于gcc、glibc和binutils模块之间的关系
1、gcc(gnu collect compiler)是一组编译工具的总称。它主要完成的工作任务是“预处理”和“编译”,以及提供了与编译器紧密相关的运行库的支持,如 libgcc_s.so、libstdc++.so等。
2、binutils提供了一系列用来创建、管理和维护二进制目标文件的工具程序,如汇编(as)、连接(ld)、静态库归档(ar)、反汇编 (objdump)、elf结构分析工具(readelf)、无效调试信息和符号的工具(strip)等。通常,binutils与gcc是紧密相集成 的,没有binutils的话,gcc是不能正常工作的。
3、glibc是gnu发布的libc库,也即c运行库。glibc是linux系统中最底层的api(应用程序开发接口),几乎其它任何的运行库 都会倚赖于glibc。glibc除了封装linux操作系统所提供的系统服务外,它本身也提供了许多其它一些必要功能服务的实现,主要的如下:
(1)string,字符串处理
(2)signal,信号处理
(3)dlfcn,管理共享库的动态加载
(4)direct,文件目录操作
(5)elf,共享库的动态加载器,也即interpreter
(6)iconv,不同字符集的编码转换
(7)inet,socket接口的实现
(8)intl,国际化,也即gettext的实现
(9)io
(10)linuxthreads
(11)locale,本地化
(12)login,虚拟终端设备的管理,及系统的安全访问
(13)malloc,动态内存的分配与管理
(14)nis
(15)stdlib,其它基本功能
二、redhat9上升级gcc
1、升级这些库时,最好不要覆盖系统中缺省的;因为这些库,尤其是glibc库,是系统中最核心的共享库和工具,如果盲目覆盖,很可能导致整个系统 瘫痪,因为一般更新glibc库时,其它所有以来libc库的共享库都需要重新被编译一遍。因此,为了调试某个程序进入glibc时,最好把glibc安 装到/usr/local/lib下。
2、首先编译glibc库。注意最好令建立一个glibc-build的目录,configure时加上–enable-add- ons=linuxthreads选项。make install安装到/usr/local下。
3、修改gcc的spec文件(/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/specs),更改ld- linux.so.2为/usr/local/lib下的新的共享库装载器。
4、编译binutils库,此时被编译出的程序会连接到/usr/local/lib下的新的libc库。注意,在configure前,需要设 置ld缺省连接的路径(LIBRARY_PATH=/usr/local/lib:/lib:/usr/lib),否则binutils会 configure出错,找不到libc中的一些符号。具体步骤如下:
(1)export LIBRARY_PATH=/usr/local/lib:/lib:/usr/lib
(2)mkdir binutils-build && cd binutils-build
(3)../binutils-2.13.90.0.18/configure
(4)make
(5)make -C ld clean
(6)make -C ld LIB_PATH=/usr/lib:/lib:/usr/local/bin(设置编译后的ld的缺省库搜索路径,后面的比前面的优先级高)
(7)make install
三、总结
1、运行时,动态库的装载依赖于ld-linux.so.6的实现,它查找共享库的顺序如下:
(1)ld-linux.so.6在可执行的目标文件中被指定,可用readelf命令查看
(2)ld-linux.so.6缺省在/usr/lib和lib中搜索;当glibc安装到/usr/local下时,它查找/usr/local /lib
(3)LD_LIBRARY_PATH环境变量中所设定的路径
(4)/etc/ld.so.conf(或/usr/local/etc/ld.so.conf)中所指定的路径,由ldconfig生成二进制的 ld.so.cache中
2、编译时,搜索库的路径顺序如下:
(1)ld-linux.so.6由gcc的spec文件中所设定
(2)gcc –print-search-dirs所打印出的路径,主要是libgcc_s.so等库。可以通过GCC_EXEC_PREFIX来设定
(3)LIBRARY_PATH环境变量中所设定的路径,或编译的命令行中指定的-L/usr/local/lib
(2)binutils中的ld所设定的缺省搜索路径顺序,编译binutils时指定。
(可以通过“ld –verbose | grep SEARCH”来查看)
3、二进制程序的搜索路径顺序为PATH环境变量中所设定。一般/usr/local/bin高于/usr/bin
4、编译时的头文件的搜索路径顺序,与library的查找顺序类似。一般/usr/local/include高于/usr/include
————————————————————————————————————
前言
如果普通编程不需要了解这些东西,如果想精确控制你的对象文件的格式或者你想查看一下文件对象里的内容以便作出某种判断,刚你可以看一下下面的工 具:objdump, nm, ar。当然,本文不可能非常详细的说明它们的使用方法和功能。如果你觉得本文不够清楚,你可以使用:man. 我的计划只是想让更多的人了解这些工具,以后在今后 的编程过程中能有所帮助。
操作系统: Linux
开始
- 库文件操作命令:ar —-非常好的东东。。让你能查看函数库里的详细情况和用多个对象文件生成一个库文件。
- 经 常用法:
- ar -t libname.a //显示所有对象文件(.o文件)的列表.例: # ar t libtest.a
libtest1.o
libtest2.o - ar -rv libname.a objfile1.o objfile2.o … objfilen.o //把objfile1.o–objfilen.o打包成一个库文件
- ar -t libname.a //显示所有对象文件(.o文件)的列表.例: # ar t libtest.a
- ar 选项
d:从库中删除模块。按模块原来的文件名指定要删除的模块。如果使用了任选项v则列出被删除的每个模块。
m:该操作是在一个库中移动成员。当库中如果有若干模块有相同的符号定义(如函数定义),则成员的位置顺序很重要。如果没有指定任选项,任何指定的成员将 移到库的最后。也可以使用’a’,’b’,或’I’任选项移动到指定的位置。
p:显示库中指定的成员到标准输出。如果指定任选项v,则在输出成员的内容前,将显示成员的名字。如果没有指定成员的名字,所有库中的文件将显示出来。
q:快速追加。增加新模块到库的结尾处。并不检查是否需要替换。’a’,’b’,或’I’任选项对此操作没有影响,模块总是追加的库的结尾处。如果使用了 任选项v则列出每个模块。 这时,库的符号表没有更新,可以用’ar s’或ranlib来更新库的符号表索引。
r:在库中插入模块(替换)。当插入的模块名已经在库中存在,则替换同名的模块。如果若干模块中有一个模块在库中不存在,ar显示一个错误消息,并不替换 其他同名模块。默认的情况下,新的成员增加在库的结尾处,可以使用其他任选项来改变增加的位置。
t:显示库的模块表清单。一般只显示模块名。
x:从库中提取一个成员。如果不指定要提取的模块,则提取库中所有的模块。
下面在看看可与操作选项结合使用的任选项:a:在库的一个已经存在的成员后面增加一个新的文件。如果使用任选项a,则应该为命令行中membername参数指定一个已经存在的成员名。
b:在库的一个已经存在的成员前面增加一个新的文件。如果使用任选项b,则应该为命令行中membername参数指定一个已经存在的成员名。
c:创建一个库。不管库是否存在,都将创建。
f:在库中截短指定的名字。缺省情况下,文件名的长度是不受限制的,可以使用此参数将文件名截短,以保证与其它系统的兼容。
i:在库的一个已经存在的成员前面增加一个新的文件。如果使用任选项i,则应该为命令行中membername参数指定一个已经存在的成员名(类似任选项 b)。
l:暂未使用
N:与count参数一起使用,在库中有多个相同的文件名时指定提取或输出的个数。
o:当提取成员时,保留成员的原始数据。如果不指定该任选项,则提取出的模块的时间将标为提取出的时间。
P:进行文件名匹配时使用全路径名。ar在创建库时不能使用全路径名(这样的库文件不符合POSIX标准),但是有些工具可以。
s:写入一个目标文件索引到库中,或者更新一个存在的目标文件索引。甚至对于没有任何变化的库也作该动作。对一个库做ar s等同于对该库做ranlib。
S:不创建目标文件索引,这在创建较大的库时能加快时间。
u:一般说来,命令ar r…插入所有列出的文件到库中,如果你只想插入列出文件中那些比库中同名文件新的文件,就可以使用该任选项。该任选项只用于r操作选项。
v:该选项用来显示执行操作选项的附加信息。
V:显示ar的版本.
- 经 常用法:
- nm –列出目标文件(.o)的符号清单。。NND,太激动了。刚知道此命令时让我三天没睡好觉。我就使劲用了一把。
- 常用法:
- nm -s filename.a/filename.o/a.out 里边所有的符号列表一清二楚。例:
# nm -s a.out
080495b8 A __bss_start
08048334 t call_gmon_start
080495b8 b completed.5751
080494b8 d __CTOR_END__
080494b4 d __CTOR_LIST__
080495ac D __data_start
080495ac W data_start
08048450 t __do_global_ctors_aux
08048360 t __do_global_dtors_aux
080495b0 D __dso_handle
080494c0 d __DTOR_END__
080494bc d __DTOR_LIST__
080494c8 d _DYNAMIC
080495b8 A _edata
080495bc A _end
0804847c T _fini
08048498 R _fp_hw
08048390 t frame_dummy
080484b0 r __FRAME_END__
08049594 d _GLOBAL_OFFSET_TABLE_
w __gmon_start__
0804844c T __i686.get_pc_thunk.bx
080482b8 T _init
080494b4 a __init_array_end
080494b4 a __init_array_start
0804849c R _IO_stdin_used
080494c4 d __JCR_END__
080494c4 d __JCR_LIST__
w _Jv_RegisterClasses
080483e0 T __libc_csu_fini
080483f0 T __libc_csu_init
U __libc_start_main@@GLIBC_2.0
080483b4 T main
080495b4 d p.5749
U puts@@GLIBC_2.0
08048310 T _start
- nm -s filename.a/filename.o/a.out 里边所有的符号列表一清二楚。例:
- 选项/属性:
-a或–debug-syms:显示调试符号。
-B:等同于–format=bsd,用来兼容MIPS的nm。
-C或–demangle:将低级符号名解码(demangle)成用户级名字。这样可以使得C++函数名具有可读性。
-D或–dynamic:显示动态符号。该任选项仅对于动态目标(例如特定类型的共享库)有意义。
-f format:使用format格式输出。format可以选取bsd、sysv或posix,该选项在GNU的nm中有用。默认为bsd。
-g或–extern-only:仅显示外部符号。
-n、-v或–numeric-sort:按符号对应地址的顺序排序,而非按符号名的字符顺序。
-p或–no-sort:按目标文件中遇到的符号顺序显示,不排序。
-P或–portability:使用POSIX.2标准输出格式代替默认的输出格式。等同于使用任选项-f posix。
-s或–print-armap:当列出库中成员的符号时,包含索引。索引的内容包含:哪些模块包含哪些名字的映射。
-r或–reverse-sort:反转排序的顺序(例如,升序变为降序)。
–size-sort:按大小排列符号顺序。该大小是按照一个符号的值与它下一个符号的值进行计算的。
-t radix或–radix=radix:使用radix进制显示符号值。radix只能为”d”表示十进制、”o”表示八进制或”x”表示十六进制。
–target=bfdname:指定一个目标代码的格式,而非使用系统的默认格式。
-u或–undefined-only:仅显示没有定义的符号(那些外部符号)。
-l或–line-numbers:对每个符号,使用调试信息来试图找到文件名和行号。对于已定义的符号,查找符号地址的行号。对于未定义符号,查找指 向符号重定位入口的行号。如果可以找到行号信息,显示在符号信息之后。
-V或–version:显示nm的版本号。
–help:显示nm的任选项。
- 常用法:
- objdump 文件命令功能强的惊人。能实现上述两个命令(ar,nm)的 很多功能。它主要是查看对象文件的内容信息。
- 常用法:
- objdump -h file<.o,.a,.out>//查看对象文件所有的节sections.例如:
# objdump -h libtest1.o
libtest1.o: file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000014 00000000 00000000 00000034 2**2
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
1 .data 00000000 00000000 00000000 00000048 2**2
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000000 00000000 00000000 00000048 2**2
ALLOC
3 .rodata 0000000e 00000000 00000000 00000048 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .comment 0000001f 00000000 00000000 00000056 2**0
CONTENTS, READONLY
5 .note.GNU-stack 00000000 00000000 00000000 00000075 2**0
CONTENTS, READONLY - objdump -t 查看对象文件所有的符号列表,相当于 nm -s objfilename,如:
# objdump -t libtest1.olibtest1.o: file format elf32-i386SYMBOL TABLE:
00000000 l df *ABS* 00000000 libtest1.c
00000000 l d .text 00000000 .text
00000000 l d .data 00000000 .data
00000000 l d .bss 00000000 .bss
00000000 l d .rodata 00000000 .rodata
00000000 l d .note.GNU-stack 00000000 .note.GNU-stack
00000000 l d .comment 00000000 .comment
00000000 g F .text 00000014 print_test1
00000000 *UND* 00000000 puts
- objdump -h file<.o,.a,.out>//查看对象文件所有的节sections.例如:
- 更多信息请查看选项:
–archive-headers
-a 显示档案库的成员信息,与 ar tv 类似 objdump -a libpcap.a
和 ar -tv libpcap.a 显示结果比较比较
显然这个选项没有什么意思。–adjust-vma=offset
When dumping information, first add offset to all
the section addresses. This is useful if the sec-
tion addresses do not correspond to the symbol
table, which can happen when putting sections at
particular addresses when using a format which can
not represent section addresses, such as a.out.-b bfdname
–target=bfdname
指定目标码格式。这不是必须的,objdump能自动识别许多格式,
比如:objdump -b oasys -m vax -h fu.o
显示fu.o的头部摘要信息,明确指出该文件是Vax系统下用Oasys
编译器生成的目标文件。objdump -i将给出这里可以指定的
目标码格式列表–demangle
-C 将底层的符号名解码成用户级名字,除了去掉所有开头
的下划线之外,还使得C++函数名以可理解的方式显示出来。–debugging
显示调试信息。企图解析保存在文件中的调试信息并以C语言
的语法显示出来。仅仅支持某些类型的调试信息。–disassemble
-d 反汇编那些应该还有指令机器码的section–disassemble-all
-D 与 -d 类似,但反汇编所有section–prefix-addresses
反汇编的时候,显示每一行的完整地址。这是一种比较老的反汇编格式。
显示效果并不理想,但可能会用到其中的某些显示,自己可以对比。–disassemble-zeroes
一般反汇编输出将省略大块的零,该选项使得这些零块也被反汇编。-EB
-EL
–endian={big|little}
这个选项将影响反汇编出来的指令。
little-endian就是我们当年在dos下玩汇编的时候常说的高位在高地址,
x86都是这种。–file-headers
-f 显示objfile中每个文件的整体头部摘要信息。–section-headers
–headers
-h 显示目标文件各个section的头部摘要信息。–help 简短的帮助信息。
–info
-i 显示对于 -b 或者 -m 选项可用的架构和目标格式列表。–section=name
-j name 仅仅显示指定section的信息–line-numbers
-l 用文件名和行号标注相应的目标代码,仅仅和-d、-D或者-r一起使用
使用-ld和使用-d的区别不是很大,在源码级调试的时候有用,要求
编译时使用了-g之类的调试编译选项。–architecture=machine
-m machine
指定反汇编目标文件时使用的架构,当待反汇编文件本身没有描述
架构信息的时候(比如S-records),这个选项很有用。可以用-i选项
列出这里能够指定的架构–reloc
-r 显示文件的重定位入口。如果和-d或者-D一起使用,重定位部分以反汇
编后的格式显示出来。–dynamic-reloc
-R 显示文件的动态重定位入口,仅仅对于动态目标文件有意义,比如某些
共享库。–full-contents
-s 显示指定section的完整内容。objdump –section=.text -s inet.o | more
–source
-S 尽可能反汇编出源代码,尤其当编译的时候指定了-g这种调试参数时,
效果比较明显。隐含了-d参数。–show-raw-insn
反汇编的时候,显示每条汇编指令对应的机器码,除非指定了
–prefix-addresses,这将是缺省选项。–no-show-raw-insn
反汇编时,不显示汇编指令的机器码,这是指定 –prefix-addresses
选项时的缺省设置。–stabs
Display the contents of the .stab, .stab.index, and
.stab.excl sections from an ELF file. This is only
useful on systems (such as Solaris 2.0) in which
.stab debugging symbol-table entries are carried in
an ELF section. In most other file formats, debug-
ging symbol-table entries are interleaved with
linkage symbols, and are visible in the –syms output.–start-address=address
从指定地址开始显示数据,该选项影响-d、-r和-s选项的输出。–stop-address=address
显示数据直到指定地址为止,该选项影响-d、-r和-s选项的输出。–syms
-t 显示文件的符号表入口。类似于nm -s提供的信息–dynamic-syms
-T 显示文件的动态符号表入口,仅仅对动态目标文件有意义,比如某些
共享库。它显示的信息类似于 nm -D|–dynamic 显示的信息。–version 版本信息
objdump –version
–all-headers
-x 显示所有可用的头信息,包括符号表、重定位入口。-x 等价于
-a -f -h -r -t 同时指定。objdump -x inet.o
- 常用法:
ar,nm,objdump,objcopy
From: http://blog.163.com/tao198352__4232/blog/static/85020645201081993325589/
如果普通编程不需要了解这些东西,如果想精确控制你的目标文件的格式或者你想查看一下文件里的内容以便作出某种判断,那么你可以看一下下面的工具:ar,nm,objdump,objcopy。具体用法请参考man在线手册。
ar基本用法
ar命令可以用来创建、修改库,也可以从库中提出单个模块。库是一单独的文件,里面包含了按照特定的结构组织起来的其它的一些文件(称做此库文件的member)。原始文件的内容、模式、时间戳、属主、组等属性都保留在库文件中。
下面是ar命令的格式:
ar [-]{dmpqrtx}[abcfilNoPsSuvV] [membername] [count] archive files…
例如我们可以用ar rv libtest.a hello.o hello1.o 来 生成一个库,库名字是test,链接时可以用-ltest链接。该库中存放了两个模块hello.o和hello1.o。选项前可以有‘-‘字符,也可以 没有。下面我们来看看命令的操作选项和任选项。现在我们把{dmpqrtx}部分称为操作选项,而[abcfilNoPsSuvV]部分称为任选项。
{dmpqrtx}中的操作选项在命令中只能并且必须使用其中一个,它们的含义如下:
- d:从库中删除模块。按模块原来的文件名指定要删除的模块。如果使用了任选项v则列出被删除的每个模块。
- m:该操作是在一个库中移动成员。当库中如果有若干模块有相同的符号定义(如函数定义),则成员的位置顺序很重要。如果没有指定任选项,任何指定的成员将移到库的最后。也可以使用’a’,’b’,或’I’任选项移动到指定的位置。
- p:显示库中指定的成员到标准输出。如果指定任选项v,则在输出成员的内容前,将显示成员的名字。如果没有指定成员的名字,所有库中的文件将显示出来。
- q:快速追加。增加新模块到库的结尾处。并不检查是否需要替换。’a’,’b’,或’I’任选项对此操作没有影响,模块总是追加的库的结尾处。如果使用了任选项v则列出每个模块。 这时,库的符号表没有更新,可以用’ar s’或ranlib来更新库的符号表索引。
- r:在库中插入模块(替换)。当插入的模块名已经在库中存在,则替换同名的模块。如果若干模块中有一个模块在库中不存在,ar显示一个错误消息,并不替换其他同名模块。默认的情况下,新的成员增加在库的结尾处,可以使用其他任选项来改变增加的位置。
- t:显示库的模块表清单。一般只显示模块名。
- x:从库中提取一个成员。如果不指定要提取的模块,则提取库中所有的模块。
下面在看看可与操作选项结合使用的任选项:
- a:在库的一个已经存在的成员后面增加一个新的文件。如果使用任选项a,则应该为命令行中membername参数指定一个已经存在的成员名。
- b:在库的一个已经存在的成员前面增加一个新的文件。如果使用任选项b,则应该为命令行中membername参数指定一个已经存在的成员名。
- c:创建一个库。不管库是否存在,都将创建。
- f:在库中截短指定的名字。缺省情况下,文件名的长度是不受限制的,可以使用此参数将文件名截短,以保证与其它系统的兼容。
- i:在库的一个已经存在的成员前面增加一个新的文件。如果使用任选项i,则应该为命令行中membername参数指定一个已经存在的成员名(类似任选项b)。
- l:暂未使用
- N:与count参数一起使用,在库中有多个相同的文件名时指定提取或输出的个数。
- o:当提取成员时,保留成员的原始数据。如果不指定该任选项,则提取出的模块的时间将标为提取出的时间。
- P:进行文件名匹配时使用全路径名。ar在创建库时不能使用全路径名(这样的库文件不符合POSIX标准),但是有些工具可以。
- s:写入一个目标文件索引到库中,或者更新一个存在的目标文件索引。甚至对于没有任何变化的库也作该动作。对一个库做ar s等同于对该库做ranlib。
- S:不创建目标文件索引,这在创建较大的库时能加快时间。
- u:一般说来,命令ar r…插入所有列出的文件到库中,如果你只想插入列出文件中那些比库中同名文件新的文件,就可以使用该任选项。该任选项只用于r操作选项。
- v:该选项用来显示执行操作选项的附加信息。
- V:显示ar的版本。
nm基本用法
nm用来列出目标文件的符号清单。下面是nm命令的格式:
nm [-a│–debug-syms] [-g│–extern-only]
[-B] [-C│–demangle[=style]] [-D│–dynamic]
[-S│–print-size] [-s│–print-armap]
[-A│-o│–print-file-name][–special-syms]
[-n│-v│–numeric-sort] [-p│–no-sort]
[-r│–reverse-sort] [–size-sort] [-u│–undefined-only]
[-t radix│–radix=radix] [-P│–portability]
[–target=bfdname] [-f format│–format=format]
[–defined-only] [-l│–line-numbers] [–no-demangle]
[-V│–version] [-X 32_64] [–help] [objfile…]
如果没有为nm命令指出目标文件,则nm假定目标文件是a.out。下面列出该命令的任选项,大部分支持”-“开头的短格式和”—”开头的长格式。
- -A、-o或–print-file-name:在找到的各个符号的名字前加上文件名,而不是在此文件的所有符号前只出现文件名一次。例如nm libtest.a的输出如下:CPThread.o:
00000068 T Main__8CPThreadPv
00000038 T Start__8CPThread
00000014 T _._8CPThread
00000000 T __8CPThread
00000000 ? __FRAME_BEGIN__
…………………………………
则nm -A 的输出如下:libtest.a:CPThread.o:00000068 T Main__8CPThreadPv
libtest.a:CPThread.o:00000038 T Start__8CPThread
libtest.a:CPThread.o:00000014 T _._8CPThread
libtest.a:CPThread.o:00000000 T __8CPThread
libtest.a:CPThread.o:00000000 ? __FRAME_BEGIN__
…………………………………………………………
- -a或–debug-syms:显示所有的符号,包括debugger-only symbols 。
- -B:等同于–format=bsd,用来兼容MIPS的nm。
- -C或–demangle:将低级符号名解析(demangle)成用户级名字。这样可以使得C++函数名具有可读性。
- –no-demangle:默认的选项,不需要将低级符号名解析成用户级名 。
- -D或–dynamic:显示动态符号。该任选项仅对于动态目标(例如特定类型的共享库)有意义。
- -f format:使用format格式输出。format可以选取bsd、sysv或posix,该选项在GNU的nm中有用。默认为bsd。
- -g或–extern-only:仅显示外部符号。
- -n、-v或–numeric-sort:按符号对应地址的顺序排序,而非按符号名的字符顺序。
- -p或–no-sort:按目标文件中遇到的符号顺序显示,不排序。
- -P或–portability:使用POSIX.2标准输出格式代替默认的输出格式。等同于使用任选项-f posix。
- -s或–print-armap:当列出库中成员的符号时,包含索引。索引的内容包含:哪些模块包含哪些名字的映射。
- -r或–reverse-sort:反转排序的顺序(例如,升序变为降序)。
- –size-sort:按大小排列符号顺序。该大小是按照一个符号的值与它下一个符号的值进行计算的。
- -t radix或–radix=radix:使用radix进制显示符号值。radix只能为”d”表示十进制、”o”表示八进制或”x”表示十六进制。
- –target=bfdname:指定一个目标代码的格式,而非使用系统的默认格式。
- -u或–undefined-only:仅显示没有定义的符号(那些外部符号)。
- –defined-only:仅显示定义的符号。
- -l或–line-numbers:对每个符号,使用调试信息来试图找到文件名和行号。对于已定义的符号,查找符号地址的行号。对于未定义符号,查找符号重定位项的行号。如果可以找到行号信息,显示在符号信息之后。
- -V或–version:显示nm的版本号。
- –help:显示nm的任选项。
对于每一个符号,nm列出其值(the symbol value),类型(the symbol type)和其名字(the symbol name)。
符号
类型
|
说明
|
A
|
该符号的值是绝对的,在以后的链接过程中,不允许进行改变。这样的符号值,常常出现在中断向量表中,例如用符号来表示各个中断向量函数在中断向量表中的位置。
|
B
|
该符号的值出现在非初始化数据段 (bss) 中。例如,在一个文件中定义全局 static int test 。则该符号 test 的类型为 b ,位于 bss section 中。其值表示该符号在 bss 段中的偏移。一般而言, bss 段分配于 RAM 中
|
C
|
该符号为 common 。 common symbol 是未初始话数据段。该符号没有包含于一个普通 section 中。只有在链接过程中才进行分配。符号的值表示该符号需要的字节数。例如在一个 c 文件中,定义 int test ,并且该符号在别的地方会被引用,则该符号类型即为 C 。否则其类型为 B 。
|
D
|
该符号位于初始话数据段中。一般来说,分配到 data section 中。例如定义全局 int baud_table[5] = {9600, 19200, 38400, 57600, 115200} ,则会分配于初始化数据段中 。
|
G
|
该符号也位于初始化数据段中。主要用于 small object 提高访问 small data object 的一种方式。
|
I
|
该符号是对另一个符号的间接引用。
|
N
|
该符号是一个 debugging 符号。
|
R
|
该符号位于只读数据区。例如定义全局 const int test[] = {123, 123}; 则 test 就是一个只读数据区的符号。注意在 cygwin 下如果使用 gcc 直接编译成 MZ 格式时,源文件中的 test 对应 _test ,并且其符号类型为 D ,即初始化数据段中。但是如果使用 m6812-elf-gcc 这样的交叉编译工具,源文件中的 test 对应目标文件的 test, 即没有添加下划线,并且其符号类型为 R 。一般而言,位于 rodata section 。值得注意的是,如果在一个函数中定义 const char *test = “abc”, const char test_int = 3 。使用 nm 都不会得到符号信息,但是字符串“ abc ”分配于只读存储器中, test 在 rodata section 中,大小为 4 。
|
S
|
符号位于非初始化数据区,用于 small object 。
|
T
|
该符号位于代码区 text section 。
|
U
|
该符号在当前文件中是未定义的,即该符号的定义在别的文件中。例如,当前文件调用另一个文件中定义的函数,在这个被调用的函数在当前就是未定义的;但是在定义它的文件中类型是 T 。但是对于全局变量来说,在定义它的文件中,其符号类型为 C ,在使用它的文件中,其类型为 U 。
|
V
|
该符号是一个 weak object 。
|
W
|
The symbol is a weak symbol that has not been specifically tagged as a weak object symbol.
|
–
|
该符号是 a.out 格式文件中的 stabs symbol 。
|
?
|
该符号类型没有定义
|
objdump基本用法
objdump有点象那个快速查看之流的工具,就是以一种可阅读的格式让你更多地了解二进制文件可能带有的附加信息。对于一般只想让自己程序跑起来的程序 员,这个命令没有更多意义,对于想进一步了解系统的程序员,应该掌握这种工具,至少你可以自己写写shellcode了,或者看看人家给的exploit 中的shellcode是什么东西。更多关于目标文件的内容分析建议看看《深入理解计算机》这本书的第二部分第七章节 。
常用法:
objdump [-a│–archive-headers]
[-b bfdname│–target=bfdname]
[-C│–demangle[=style] ]
[-d│–disassemble]
[-D│–disassemble-all]
[-z│–disassemble-zeroes]
[-EB│-EL│–endian={big │ little }]
[-f│–file-headers]
[–file-start-context]
[-g│–debugging]
[-e│–debugging-tags]
[-h│–section-headers│–headers]
[-i│–info]
[-j section│–section=section]
[-l│–line-numbers]
[-S│–source]
[-m machine│–architecture=machine]
[-M options│–disassembler-options=options]
[-p│–private-headers]
[-r│–reloc]
[-R│–dynamic-reloc]
[-s│–full-contents]
[-W│–dwarf]
[-G│–stabs]
[-t│–syms]
[-T│–dynamic-syms]
[-x│–all-headers]
[-w│–wide]
[–start-address=address]
[–stop-address=address]
[–prefix-addresses]
[–[no-]show-raw-insn]
[–adjust-vma=offset]
[–special-syms]
[-V│–version]
[-H│–help]
objfile…
选项详解:
–archive-headers
-a 显示档案库的成员信息,与 ar tv 类似
objdump -a libpcap.a
和 ar -tv libpcap.a 显示结果比较比较
显然这个选项没有什么意思。
–adjust-vma=offset
When dumping information, first add offset to all
the section addresses. This is useful if the sec-
tion addresses do not correspond to the symbol
table, which can happen when putting sections at
particular addresses when using a format which can
not represent section addresses, such as a.out.
-b bfdname
–target=bfdname
指定目标码格式。这不是必须的,objdump能自动识别许多格式,
比如:objdump -b oasys -m vax -h fu.o
显示fu.o的头部摘要信息,明确指出该文件是Vax系统下用Oasys
编译器生成的目标文件。objdump -i将给出这里可以指定的
目标码格式列表
–demangle
-C 将底层的符号名解码成用户级名字,除了去掉所有开头
的下划线之外,还使得C++函数名以可理解的方式显示出来。
–debugging
显示调试信息。企图解析保存在文件中的调试信息并以C语言
的语法显示出来。仅仅支持某些类型的调试信息。
–disassemble
-d 反汇编那些含有指令机器码的section
–disassemble-all
-D 与 -d 类似,但反汇编所有section
–prefix-addresses
反汇编的时候,显示每一行的完整地址。这是一种比较老的反汇编格式。
显示效果并不理想,但可能会用到其中的某些显示,自己可以对比。
–disassemble-zeroes
一般反汇编输出将省略大块的零,该选项使得这些零块也被反汇编。
-EB
-EL
–endian={big|little}
这个选项将影响反汇编出来的指令。
little-endian就是我们当年在dos下玩汇编的时候常说的高位在高地址,
x86都是这种。
–file-headers
-f 显示objfile中每个文件的整体头部摘要信息。
–section-headers
–headers
-h 显示目标文件各个section的头部摘要信息。
–help 简短的帮助信息。
–info
-i 显示对于 -b 或者 -m 选项可用的架构和目标格式列表。
–section=name
-j name 仅仅显示指定section的信息
–line-numbers
-l 用文件名和行号标注相应的目标代码,仅仅和-d、-D或者-r一起使用
使用-ld和使用-d的区别不是很大,在源码级调试的时候有用,要求
编译时使用了-g之类的调试编译选项。
–architecture=machine
-m machine
指定反汇编目标文件时使用的架构,当待反汇编文件本身没有描述
架构信息的时候(比如S-records),这个选项很有用。可以用-i选项
列出这里能够指定的架构
–reloc
-r 显示文件的重定位入口。如果和-d或者-D一起使用,重定位部分以反汇
编后的格式显示出来。
–dynamic-reloc
-R 显示文件的动态重定位入口,仅仅对于动态目标文件有意义,比如某些
共享库。
–full-contents
-s 显示指定section的完整内容。
objdump –section=.text -s inet.o | more
–source
-S 尽可能反汇编出源代码,尤其当编译的时候指定了-g这种调试参数时,
效果比较明显。隐含了-d参数。
–show-raw-insn
反汇编的时候,显示每条汇编指令对应的机器码,除非指定了
–prefix-addresses,这将是缺省选项。
–no-show-raw-insn
反汇编时,不显示汇编指令的机器码,这是指定 –prefix-addresses
选项时的缺省设置。
–stabs
Display the contents of the .stab, .stab.index, and
.stab.excl sections from an ELF file. This is only
useful on systems (such as Solaris 2.0) in which
.stab debugging symbol-table entries are carried in
an ELF section. In most other file formats, debug-
ging symbol-table entries are interleaved with
linkage symbols, and are visible in the –syms output.
–start-address=address
从指定地址开始显示数据,该选项影响-d、-r和-s选项的输出。
–stop-address=address
显示数据直到指定地址为止,该选项影响-d、-r和-s选项的输出。
–syms
-t 显示文件的符号表入口。类似于nm提供的信息
–dynamic-syms
-T 显示文件的动态符号表入口,仅仅对动态目标文件有意义,比如某些
共享库。它显示的信息类似于 nm -D|–dynamic 显示的信息。
–version 版本信息
objdump –version
–all-headers
-x 显示所有可用的头信息,包括符号表、重定位入口。-x 等价于
-a -f -h -r -t 同时指定。
objdump -x inet.o
objcopy 基本用法
objcopy把一种目标文件中的内容复制到另一种类型的目标文件中.
(1)将图像编译到可执行文件内
Q: 如何将一个二进制文件,比如图片,词典一类的东西做为.o文件,直接链接到可执行文件内部呢?
A:
$ objcopy -I binary -O elf32-i386 -B i386 14_95_13.jpg image.o
$ gcc image.o tt.o -o tt
$ nm tt | grep 14_95
0805d6c7 D _binary_14_95_13_jpg_end
00014213 A _binary_14_95_13_jpg_size
080494b4 D _binary_14_95_13_jpg_start
(2)使用objcopy把不用的信息去掉:
$ objcopy -R .comment -R .note halo halo.min
(3)
$ objcopy -R .note -R .comment -S -O binary xyb xyb.bin
-R .note -R .comment 表示移掉 .note 与 .comment 段
-S 表示移出所有的标志及重定位信息
-O binary xyb xyb.bin 表示由xyb生成二进制文件xyb.bin
objcopy工具使用指南
objcopy Utility
objcopy [ -F bfdname | –target=bfdname ]
[ -I bfdname | –input-target=bfdname ]
[ -O bfdname | –output-target= bfdname ]
[ -S | –strip-all ] [ -g | –strip-debug ]
[ -K symbolname | –keep-symbol= symbolname ]
[ -N symbolname | –strip-symbol= symbolname ]
[ -L symbolname | –localize-symbol= symbolname ]
[ -W symbolname | –weaken-symbol= symbolname ]
[ -x | –discard-all ] [ -X | –discard-locals ]
[ -b byte | –byte= byte ]
[ -i interleave | –interleave= interleave ]
[ -R sectionname | –remove-section= sectionname ]
[ -p | –preserve-dates ] [ –debugging ]
[ –gap-fill= val ] [ –pad-to= address ]
[ –set-start= val ] [ –adjust-start= incr ]
[ –change-address= incr ]
[ –change-section-address= section{=,+,-} val ]
[ –change-warnings ] [ –no-change-warnings ]
[ –set-section-flags= section= flags ]
[ –add-section= sectionname= filename ]
[ –change-leading char ] [–remove-leading-char ]
[ –weaken ]
[ -v | –verbose ] [ -V | –version ] [ –help ]
input-file [ outfile ]
GNU 实用工具程序objcopy的作用是拷贝一个目标文件的内容到另一个目标文件中。Objcopy使用GNU BFD库去读或写目标文件。Objcopy可以使用不同于源目标文件的格式来写目的目标文件(也即是说可以将一种格式的目标文件转换成另一种格式的目标文 件)。通过以上命令行选项可以控制Objcopy的具体操作。
Objcopy在进行目标文件的转换时,将生成一个临时文件,转换完成后就将这个临 时文件删掉。Objcopy使用BFD做转换工作。如果没有明确地格式要求,则Objcopy将访问所有在BFD库中已经描述了的并且它可以识别的格式, 请参见《GNUpro Decelopment Tools》中“using ld”一章中“BFD库”部分和“BFD库中规范的目标文件格式”部分。
通过使用srec作为输出目标(使用命令行选项-o srec),Objcopy可以产生S记录格式文件。
通 过使用binary作为输出目标(使用命令行选项-o binary),Objcopy可以产生原始的二进制文件。使用Objcopy产生一个原始的二进制文件,实质上是进行了一回输入目标文件内容的内存转 储。所有的符号和重定位信息都将被丢弃。内存转储起始于输入目标文件中那些将要拷贝到输出目标文件去的部分的最小虚地址处。
使用Objcopy生成S记录格式文件或者原始的二进制文件的过程中,-S选项和-R选项可能会比较有用。-S选项是用来删掉包含调试信息的部分,-R选项是用来删掉包含了二进制文件不需要的内容的那些部分。
input-file
outfile
参 数input-file和outfile分别表示输入目标文件(源目标文件)和输出目标文件(目的目标文件)。如果在命令行中没有明确地指定 outfile,那么Objcopy将创建一个临时文件来存放目标结果,然后使用input-file的名字来重命名这个临时文件(这时候,原来的 input-file将被覆盖)。
-I bfdname
–input-target=bfdname
明确告诉Objcopy,源文件的格式是什么,bfdname是BFD库中描述的标准格式名。这样做要比“让Objcopy自己去分析源文件的格式,然后去和BFD中描述的各种格式比较,通过而得知源文件的目标格式名”的方法要高效得多。
-O bfdname
–output-target= bfdname
使用指定的格式来写输出文件(即目标文件),bfdname是BFD库中描述的标准格式名。
-F bfdname
–target= bfdname
明确告诉Objcopy,源文件的格式是什么,同时也使用这个格式来写输出文件(即目标文件),也就是说将源目标文件中的内容拷贝到目的目标文件的过程中,只进行拷贝不做格式转换,源目标文件是什么格式,目的目标文件就是什么格式。
-R sectionname
–remove-section= sectionname
从输出文件中删掉所有名为sectionname的段。这个选项可以多次使用。
注意:不恰当地使用这个选项可能会导致输出文件不可用。
-S
–strip-all (strip 剥去、剥)
不从源文件中拷贝重定位信息和符号信息到输出文件(目的文件)中去。
-g
–strip-debug
不从源文件中拷贝调试符号到输出文件(目的文件)中去。
–strip-undeeded
剥去所有在重定位处理时所不需要的符号。
-K symbolname
–keep-symbol= symbolname
仅从源文件中拷贝名为symbolname的符号。这个选项可以多次使用。
-N symbolname
–strip-symbol= symbolname
不从源文件中拷贝名为symbolname的符号。这个选项可以多次使用。它可以和其他的strip选项联合起来使用(除了-K symbolname | –keep-symbol= symbolname外)。
-L symbolname
–localize-symbol= symbolname
使名为symbolname的符号在文件内局部化,以便该符号在该文件外部是不可见的。这个选项可以多次使用。
-W symbolname
-weaken-symbol= symbolname
弱化名为symbolname的符号。这个选项可以多次使用。
-x
–discard-all (discard 丢弃、抛弃)
不从源文件中拷贝非全局符号。
-X
–discard-locals
不从源文件中拷贝又编译器生成的局部符号(这些符号通常是L或 . 开头的)。
-b byte
–byte= byte
Keep only every byte th byte of the input file (header data is not affected). byte can be
in the range from 0 to interleave-1, where interleave is given by the -i or
–interleave option, or the default of 4. This option is useful for creating files to
program ROM . It is typically used with an srec output target.
-i interleave
–interleave= interleave (interleave 隔行、交叉)
Only copy one out of every interleave bytes. Select which byte to copy with the
-b or –byte option. The default is 4. objcopy ignores this option if you do not
specify either -b or –byte.
-p
–preserve-dates (preserve 保存、保持)
设置输出文件的访问和修改日期和输入文件相同。
[ –debugging ]
如果可能的话,转换调试信息。因为只有特定的调试格式被支持,以及这个转换过程要耗费一定的时间,所以这个选项不是默认的。
–gap-fill= val
使用内容val填充段与段之间的空隙。通过增加段的大小,在地址较低的一段附加空间中填充内容val来完成这一选项的功能。
–pad-to= address
填 充输出文件到虚拟地址address。通过增加输出文件中最后一个段的大小,在输出文件中最后一段的末尾和address之间的这段附加空间中,用 –gap-fill= val选项中指定的内容val来填充(默认内容是0,即没有使用–gap-fill= val选项的情况下)。
–set-start= val
设置新文件(应该是输出文件吧?)的起始地址为val。不是所有的目标文件格式都支持设置起始地址。
–change-start = incr
–adjust-start= incr
通过增加值incr来改变起始地址。不是所有的目标文件格式都支持设置起始地址。
–change-addresses incr
–adjust-vma incr
Change the VMA and LMA addresses of all sections, section., as well as the
start address, by adding incr. Some object file formats do not permit section
addresses to be changed arbitrarily.
通过加上一个值incr,改变所有段的VMA(Virtual Memory Address运行时地址)和LMA(Load Memory Address装载地址),以及起始地址。某些目标文件格式不允许随便更改段的地址。
–change-section-address section{=,+,-} val
–adjust-section-vma section{=,+,-} val
设 置或者改变名为section的段的VMA(Virtual Memory Address运行时地址)和LMA(Load Memory Address装载地址)。如果这个选项中使用的是“=”,那么名为section的段的VMA(Virtual Memory Address运行时地址)和LMA(Load Memory Address装载地址)将被设置成val;如果这个选项中使用的是“-”或者“+”,那么上述两个地址将被设置或者改变成这两个地址的当前值减去或加上 val后的值。如果在输入文件中名为section的段不存在,那么Objcopy将发出一个警告,除非–no-change-warnings选项被 使用。
这里的段地址设置和改变都是输出文件中的段相对于输入文件中的段而言的。例如:
(1)–change-section-address .text = 10000
这里是指将输入文件(即源文件)中名为.text的段拷贝到输出文件中后,输出文件中的.text段的VMA(Virtual Memory Address运行时地址)和LMA(Load Memory Address装载地址)将都被设置成10000。
(2)–change-section-address .text + 100
这 里是指将输入文件(即源文件)中名为.text的段拷贝到输出文件中后,输出文件中的.text段的VMA(Virtual Memory Address运行时地址)和LMA(Load Memory Address装载地址)将都被设置成以前输入文件中.text段的地址(当前地址)加上100后的值。
–change-section-lma section{=,+,-} val
仅 设置或者改变名为section的段的LMA(Load Memory Address装载地址)。一个段的LMA是程序被加载时,该段将被加载到的一段内存空间的首地址。通常LMA和VMA(Virtual Memory Address运行时地址)是相同的,但是在某些系统中,特别是在那些程序放在ROM的系统中,LMA和VMA是不相同的。如果这个选项中使用的是 “=”,那么名为section的段的LMA(Load Memory Address装载地址)将被设置成val;如果这个选项中使用的是“-”或者“+”,那么LMA将被设置或者改变成这两个地址的当前值减去或加上val 后的值。如果在输入文件中名为section的段不存在,那么Objcopy将发出一个警告,除非–no-change-warnings选项被使用。
–change-section-vma section{=,+,-} val
仅 设置或者改变名为section的段的VMA(Load Memory Address装载地址)。一个段的VMA是程序运行时,该段的定位地址。通常VMA和LMA(Virtual Memory Address运行时地址)是相同的,但是在某些系统中,特别是在那些程序放在ROM的系统中,LMA和VMA是不相同的。如果这个选项中使用的是 “=”,那么名为section的段的LMA(Load Memory Address装载地址)将被设置成val;如果这个选项中使用的是“-”或者“+”,那么LMA将被设置或者改变成这两个地址的当前值减去或加上val 后的值。如果在输入文件中名为section的段不存在,那么Objcopy将发出一个警告,除非–no-change-warnings选项被使用。
–change-warnings
–adjust-warnings
如 果命令行中使用了–change-section-address section{=,+,-} val或者–adjust-section-vma section{=,+,-} val,又或者–change-section-lma section{=,+,-} val,又或者–change-section-vma section{=,+,-} val,并且输入文件中名为section的段不存在,则Objcopy发出警告。这是默认的选项。
–no-chagne-warnings
–no-adjust-warnings
如 果命令行中使用了–change-section-address section{=,+,-} val或者–adjust-section-vma section{=,+,-} val,又或者–change-section-lma section{=,+,-} val,又或者–change-section-vma section{=,+,-} val,即使输入文件中名为section的段不存在, Objcopy也不会发出警告。
–set-section-flags section=flags
为为section的段设置一个标识。这个flags变量的可以取逗号分隔的多个标识名字符串(这些标识名字符串是能够被Objcopy程序所识别的),合法的标识名有alloc,load,readonly,code,data和rom。
You can set the contents flag for a section which does not havecontents, but it is not meaningful to clear the contents flag of a section which does have contents; just remove the section instead. Not all flags are meaningful for all object file formats.
–add-section sectionname=filename
进 行目标文件拷贝的过程中,在输出文件中增加一个名为sectionname的新段。这个新增加的段的内容从文件filename得到。这个新增加的段的大 小就是这个文件filename的大小。只要输出文件的格式允许该文件的段可以有任意的段名(段名不是标准的,固定的),这个选项才能使用。
–change-leading-char
Some object file formats use special characters at the start of symbols. The most
common such character is underscore, which compilers often add before every
symbol. This option tells objcopy to change the leading character of every
symbol when it converts between object file formats. If the object file formats use
the same leading character, this option has no effect. Otherwise, it will add a
character, or remove a character, or change a character, as appropriate.
–remove-leading-char
If the first character of a global symbol is a special symbol leading character used
by the object file format, remove the character. The most common symbol leading
character is underscore. This option will remove a leading underscore from all
global symbols. This can be useful if you want to link together objects of different
file formats with different conventions for symbol names.
–weaken
Change all global symbols in the file to be weak. This can be useful when building
an object that will be linked against other objects using the -R option to the linker.
This option is only effective when using an object file format that supports weak
symbols.
-V
–version
Show the version number of objcopy.
-v
–verbose
Verbose output: list all object files modified. In the case of archives, objcopy -V
lists all members of the archive.
–help
Show a summary of the options to objcopy.
readelf基本用法
readelf 负责显示ELF文件的信息
Usage: readelf <option(s)> elf-file(s)
Display information about the contents of ELF format files
Options are:
-a –all 全部 Equivalent to: -h -l -S -s -r -d -V -A -I
-h –file-header 文件头 Display the ELF file header
-l –program-headers 程序 Display the program headers
–segments An alias for –program-headers
-S –section-headers 段头 Display the sections’ header
–sections An alias for –section-headers
-e –headers 全部头 Equivalent to: -h -l -S
-s –syms 符号表 Display the symbol table
–symbols An alias for –syms
-n –notes 内核注释 Display the core notes (if present)
-r –relocs 重定位 Display the relocations (if present)
-u –unwind Display the unwind info (if present)
-d –dynamic 动态段 Display the dynamic segment (if present)
-V –version-info 版本 Display the version sections (if present)
-A –arch-specific CPU构架 Display architecture specific information (if any).
-D –use-dynamic 动态段 Use the dynamic section info when displaying symbols
-x –hex-dump=<number> 显示 段内内容Dump the contents of section <number>
-w[liaprmfFso] or
–debug-dump[=line,=info,=abbrev,=pubnames,=ranges,=macro,=frames,=str,=loc]
显示DWARF2调试段内容 Display the contents of DWARF2 debug sections
-I –histogram Di
发表评论
要发表评论,您必须先登录。