OBJ文件格式分析工具: objdump, nm,ar

首先简要阐述关于gcc、glibc和 binutils模块之间的关系linux

1、关于gcc、glibc和binutils模块之间的关系c++

一、gcc(gnu collect compiler)是一组编译工具的总称。它主要完成的工做任务是“预处理”和“编译”,以及提供了与编译器紧密相关的运行库的支持,如 libgcc_s.so、libstdc++.so等。编程

二、binutils提供了一系列用来建立、管理和维护二进制目标文件的工具程序,如汇编(as)、链接(ld)、静态库归档(ar)、反汇编 (objdump)elf结构分析工具(readelf)无效调试信息和符号的工具(strip)等。一般,binutils与gcc是紧密相集成 的,没有binutils的话,gcc是不能正常工做的api

三、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)nissass

(15)stdlib,其它基本功能
 安全

2、redhat9上升级gcc架构

一、升级这些库时,最好不要覆盖系统中缺省的;由于这些库,尤为是glibc库,是系统中最核心的共享库和工具,若是盲目覆盖,极可能致使整个系统 瘫痪,由于通常更新glibc库时,其它全部以来libc库的共享库都须要从新被编译一遍。所以,为了调试某个程序进入glibc时,最好把glibc安 装到/usr/local/lib下。app

二、首先编译glibc库。注意最好令创建一个glibc-build的目录,configure时加上--enable-add- ons=linuxthreads选项。make install安装到/usr/local下。socket

三、修改gcc的spec文件(/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/specs),更改ld- linux.so.2为/usr/local/lib下的新的共享库装载器。函数

四、编译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

 

3、总结

一、运行时,动态库的装载依赖于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中

二、编译时,搜索库的路径顺序以下:
(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”来查看)

三、二进制程序的搜索路径顺序为PATH环境变量中所设定。通常/usr/local/bin高于/usr/bin

四、编译时的头文件的搜索路径顺序,与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 选项
      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
    • 选项/属性:
      -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.o

        libtest1.o:     file format elf32-i386

        SYMBOL 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
    • 更多信息请查看选项: --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
相关文章
相关标签/搜索