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 选项
      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


posted on 2017-07-07 16:01  ljbguanli  阅读(437)  评论(0编辑  收藏  举报