Chinaunix首页 | 论坛 | 博客
  • 博客访问: 525175
  • 博文数量: 51
  • 博客积分: 345
  • 博客等级: 民兵
  • 技术积分: 534
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-21 12:02
个人简介

文章分类

全部博文(51)

文章存档

2023年(2)

2022年(1)

2021年(7)

2020年(10)

2019年(2)

2016年(20)

2015年(5)

2014年(1)

2011年(3)

我的朋友

分类: LINUX

2016-08-22 15:46:10

nm工具可以用来查看符号信息;检索包含在目标文件里的符号;
objcopy:可以用来对段信息做修改;
od 工具格式化为字符串输出
ar工具 建立、修改、提取归档文件;归档文件是包含多个文件内容的一个大文件,其结构保证了可以恢复原始内容;
ldd命令可以查看模块依赖哪些共享库;
strings 显示文件中可能的字符串;
ltrace 可以跟踪库函数调用
strace 跟踪系统调用
addr2line 从地址获取文件名和行号;


od -t x1z -A x test_define | head -5
十六进制(字节显示), z : 输出ASC,  以十六基数显示下标;


~/arm-marvell-linux-uclibcgnueabi-readelf -S vmlinux    //内核段信息
~/arm-marvell-linux-uclibcgnueabi-objdump  vmlinux -ds -j .init.arch.info     //查看某一个段具体内容

objdump  -h XXX 各个段的基本信息;
objdump  -x XXX  
-s将段的内容以十六机制打印出来,
-d将所有包含指令的段反汇编;


.rodata 只读数据段;
.comment 注释信息段
.note.GNU-stack 堆栈提示段


CONTENTS, ALLOC,等表示段的各种属性;
有一个专门的命令size,来查看ELF文件的代码段、数据段、BSS段的长度;
$size XXX




常用段名
说明
.comment
存放是编译器版本信息,比如字符串:“GCC:(GNU)4.2.0”
.debug
调试信息
.dynamic
动态链接信息
.hash
符号哈希表
.line
调试时的行号表,即源代码行号与编译后指令的对应表
.strtab
String Table 字符串表,用于存储ELF文件中用到的各种字符串
.symtab
symbol table 符号表
.shsrtab
section string table 段名表
.plt
.got
动态链接的跳转表和全局入口表
.init
.fini
程序初始化和终结代码段
.note
额外的编译器信息,比如程序的公司名、发布版本号等;


若想将图片,MP3,词典一类的作为目标文件可以借助,objcopy工具;



[root@localhost code]$readelf  -h test
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 03 00 00 00 00 00 00 00 00
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - Linux
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Intel 80386
  Version:                           0x1
  Entry point address:               0x8048300
  Start of program headers:          52 (bytes into file)
  Start of section headers:          2176 (bytes into file)    //段表的位置,位于 .shstrtab和.symtab之间;
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         8
  Size of section headers:           40 (bytes)
  Number of section headers:         30
  Section header string table index: 27

段表: section  header table


[root@localhost code]$readelf  -S test
There are 30 section headers, starting at offset 0x880:

Section Headers:  
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .interp           PROGBITS        08048134 000134 000013 00   A  0   0  1
  [ 2] .note.ABI-tag     NOTE            08048148 000148 000020 00   A  0   0  4
  [ 3] .note.gnu.build-i NOTE            08048168 000168 000024 00   A  0   0  4
  [ 4] .gnu.hash         GNU_HASH        0804818c 00018c 000020 04   A  5   0  4
  [ 5] .dynsym           DYNSYM          080481ac 0001ac 000050 10   A  6   1  4
  [ 6] .dynstr           STRTAB          080481fc 0001fc 00004a 00   A  0   0  1
  [ 7] .gnu.version      VERSYM          08048246 000246 00000a 02   A  5   0  2
  [ 8] .gnu.version_r    VERNEED         08048250 000250 000020 00   A  6   1  4
  [ 9] .rel.dyn          REL             08048270 000270 000008 08   A  5   0  4
  [10] .rel.plt          REL             08048278 000278 000018 08   A  5  12  4
  [11] .init             PROGBITS        08048290 000290 000030 00  AX  0   0  4
  [12] .plt              PROGBITS        080482c0 0002c0 000040 04  AX  0   0  4
  [13] .text             PROGBITS        08048300 000300 00017c 00  AX  0   0 16
  [14] .fini             PROGBITS        0804847c 00047c 00001c 00  AX  0   0  4
  [15] .rodata           PROGBITS        08048498 000498 000019 00   A  0   0  4
  [16] .eh_frame_hdr     PROGBITS        080484b4 0004b4 00001c 00   A  0   0  4
  [17] .eh_frame         PROGBITS        080484d0 0004d0 000068 00   A  0   0  4
  [18] .ctors            PROGBITS        08049538 000538 000008 00  WA  0   0  4
  [19] .dtors            PROGBITS        08049540 000540 000008 00  WA  0   0  4
  [20] .jcr              PROGBITS        08049548 000548 000004 00  WA  0   0  4
  [21] .dynamic          DYNAMIC         0804954c 00054c 0000c8 08  WA  6   0  4
  [22] .got              PROGBITS        08049614 000614 000004 04  WA  0   0  4
  [23] .got.plt          PROGBITS        08049618 000618 000018 04  WA  0   0  4
  [24] .data             PROGBITS        08049630 000630 000018 00  WA  0   0  4
  [25] .bss              NOBITS          08049648 000648 000008 00  WA  0   0  4
  [26] .comment          PROGBITS        00000000 000648 00013b 00      0   0  1
  [27] .shstrtab         STRTAB          00000000 000783 0000fc 00      0   0  1
  [28] .symtab           SYMTAB          00000000 000d30 000430 10     29  46  4
  [29] .strtab           STRTAB          00000000 001160 000208 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)
[root@localhost code]$readelf  -h test

type 段类型:
     PROGBITS       程序段、代码段、数据段
     SYMTAB         表示该段内容为符号表
     STRTAB          该段内容为字符串表;
     RELA               重定位表;包含重定位信息;
     HASH               符号表的hash表;
     DYNAMIC     动态链接信息;
     NOTE          提示信息;
     NOBITS          表示该段在文件中没内容
     REL               该段包含重定位信息;
     SHLIB          保留
     DYNSYM          动态链接的符号表

Lk \ Inf :
section address alignment  段地址对齐;
AI为0或1表示无对齐要求,若为4,表示对齐为2的4次方,即16对齐;

section entry size   ES: 有些段包含了固定大小的项,由ES表示; 0表示不含固定大小项;


重定位表:

  [ 5] .dynsym           DYNSYM          080481ac 0001ac 000050 10   A  6   1  4
  [ 6] .dynstr           STRTAB          080481fc 0001fc 00004a 00   A  0   0  1
  [ 7] .gnu.version      VERSYM          08048246 000246 00000a 02   A  5   0  2
  [ 8] .gnu.version_r    VERNEED         08048250 000250 000020 00   A  6   1  4
  [ 9] .rel.dyn          REL             08048270 000270 000008 08   A  5   0  4
  [10] .rel.plt          REL             08048278 000278 000018 08   A  5  12  4

  [12] .plt              PROGBITS        080482c0 0002c0 000040 04  AX  0   0  4

.rel.plt    Lk == 5, 表示符号表下标为.dynsym, Inf==12表示其作用的段为plt;

在链接中,将函数和变量称为符号 Symbol, 函数名和变量名就是符号名 Symbol name;


链接接口---符号


[root@localhost code]$readelf  -s test

Symbol table '.dynsym' contains 5 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
     2: 00000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.0 (2)
     3: 00000000     0 FUNC    GLOBAL DEFAULT  UND puts@GLIBC_2.0 (2)
     4: 0804849c     4 OBJECT  GLOBAL DEFAULT   15 _IO_stdin_used

Symbol table '.symtab' contains 67 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 08048134     0 SECTION LOCAL  DEFAULT    1
     2: 08048148     0 SECTION LOCAL  DEFAULT    2
......
    25: 08049648     0 SECTION LOCAL  DEFAULT   25
    26: 00000000     0 SECTION LOCAL  DEFAULT   26
    27: 00000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
    28: 08049538     0 OBJECT  LOCAL  DEFAULT   18 __CTOR_LIST__
    29: 08049540     0 OBJECT  LOCAL  DEFAULT   19 __DTOR_LIST__
    30: 08049548     0 OBJECT  LOCAL  DEFAULT   20 __JCR_LIST__
    31: 08048330     0 FUNC    LOCAL  DEFAULT   13 __do_global_dtors_aux
    32: 08049648     1 OBJECT  LOCAL  DEFAULT   25 completed.5934
    33: 0804964c     4 OBJECT  LOCAL  DEFAULT   25 dtor_idx.5936
    34: 08048390     0 FUNC    LOCAL  DEFAULT   13 frame_dummy
    35: 00000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
    36: 0804953c     0 OBJECT  LOCAL  DEFAULT   18 __CTOR_END__
    37: 08048534     0 OBJECT  LOCAL  DEFAULT   17 __FRAME_END__
    38: 08049548     0 OBJECT  LOCAL  DEFAULT   20 __JCR_END__
    39: 08048450     0 FUNC    LOCAL  DEFAULT   13 __do_global_ctors_aux
    40: 00000000     0 FILE    LOCAL  DEFAULT  ABS test.c
    41: 08049644     4 OBJECT  LOCAL  DEFAULT   24 i.2167
    42: 08049618     0 OBJECT  LOCAL  HIDDEN   23 _GLOBAL_OFFSET_TABLE_
    43: 08049538     0 NOTYPE  LOCAL  HIDDEN   18 __init_array_end
    44: 08049538     0 NOTYPE  LOCAL  HIDDEN   18 __init_array_start
    45: 0804954c     0 OBJECT  LOCAL  HIDDEN   21 _DYNAMIC
    46: 08049630     0 NOTYPE  WEAK   DEFAULT   24 data_start
    47: 080483e0     5 FUNC    GLOBAL DEFAULT   13 __libc_csu_fini
    48: 08048300     0 FUNC    GLOBAL DEFAULT   13 _start
    49: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
    50: 00000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses
    51: 08048498     4 OBJECT  GLOBAL DEFAULT   15 _fp_hw
    52: 0804847c     0 FUNC    GLOBAL DEFAULT   14 _fini
    53: 00000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@@GLIBC_
    54: 08049634    13 OBJECT  GLOBAL DEFAULT   24 String
    55: 0804849c     4 OBJECT  GLOBAL DEFAULT   15 _IO_stdin_used
    56: 08049630     0 NOTYPE  GLOBAL DEFAULT   24 __data_start
    57: 080484a0     0 OBJECT  GLOBAL HIDDEN   15 __dso_handle
    58: 08049544     0 OBJECT  GLOBAL HIDDEN   19 __DTOR_END__
    59: 080483f0    90 FUNC    GLOBAL DEFAULT   13 __libc_csu_init
    60: 08049648     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
    61: 08049650     0 NOTYPE  GLOBAL DEFAULT  ABS _end
    62: 00000000     0 FUNC    GLOBAL DEFAULT  UND puts@@GLIBC_2.0
    63: 08049648     0 NOTYPE  GLOBAL DEFAULT  ABS _edata
    64: 0804844a     0 FUNC    GLOBAL HIDDEN   13 __i686.get_pc_thunk.bx
    65: 080483b4    36 FUNC    GLOBAL DEFAULT   13 main
    66: 08048290     0 FUNC    GLOBAL DEFAULT   11 _init

Value: 符号地址,与符号类型有关,可能是一个绝对值,也能是地址;
Size:符号大小,对于包含数据的符号,这个值是数据类型的大小;若对应字符串,则是字符串大小;
Type:
     NOTYPE: 未知
     OBJECT: 是个数据对象,比如:变量或数组
     FUNC: 函数或其他可执行代码
     SECTION: 表示一个段;
     FILE: 表示文件名,
Bind:
     GLOBAL 全局符号,外部可见;
     WEAK:弱引用
     LOCAL:局部符号,外部不可见
Vis: 这个说C/C++没使用, 看来不是呃呃呃额额;
Ndx:若符号定义在本目标文件中,那么这个表示符号所在段在段表中的下标;还有一些特殊值;
     ABS: 表示该符号包含了一个绝对值;
     COMMON: 表示该符号是一个COMMON块类型的符号,一般来说,未初始化的全局符号定义就是这种类型的;
     UNDEF:在本目标函数引用,但是定义在其他目标文件中;

Name


C++为了兼容C,在符号的管理上,C++有一个声明C的符号“extern “C” ”的用法;这样C++的名称修饰机制就不会起作用;
C语言不支持extern用法,为了避免使用两套头文件, C++定义了一个“__cplusplus”宏, C++编译器在编译C++程序时,默认定义这个宏,

弱符号/强符号
通过“__attribute__((weak))”来定义弱符号,

强引用/弱引用   “__attribute__((weakref))”
弱引用和弱符号主要用于库的链接过程;

DWARF: debug with arbitrary record format
VMA: virtual memory address
LMA: load memory address


编译器将未初始化的全局变量定义为弱符号;

编译器为什么不把未初始化的全局变量当做未初始化的局部变量 处理放在bss段中, 而是标记为COMMON类型的变量?

在编译单元 无法确定弱符号占用的空间,但在连接过程中弱符号占用空间就确定了,这时弱符号在最终输出文件的bss段为其分配空间;未初始化全局变量最终还是放在BSS段中。

ABI: application binary interface
影响ABI因素:硬件,编程语言,编译器,连接器,OS等;
对于C语言来说以下几个因素会影响ABI兼容:
  • 内置类型大小和存储器中的放置方式
  • 组合类型的存储方式和内存分布;
  • 外部符号和用户定义符号之间的命名方式和解析方式;
  • 函数调用方式:参数入栈顺序、返回值等;
  • 堆栈分布,局部变量、参数在堆栈的位置,参数传递方式等;
  • 寄存器使用约定;


4.5 静态库链接
使用ar工具可以看文件包含哪些目标文件
ar -t   /lib/libc.a   //t            - display contents of archive  显示组成该文件的小文件
ar -x  /lib/libc.a   // x[o]         - extract file(s) from the archive     解压出文件

ld连接器会自动寻找所需要的符号及它们所在的目标文件,将这些目标文件从libc.a中解压出来,最终将它们链接在一起成为一个可执行文件。

gcc 添加 --verbose可以将整个编译链接过程的中间步骤打印出来;

[lvjianlin@sw1-dev code]$ gcc -o test_define --verbose test_define.c
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/i686-redhat-linux/4.7.2/lto-wrapper
Target: i686-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl= --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --disable-build-with-cxx --disable-build-poststage1-with-cxx --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-languages=c,c++,objc,obj-c++,java,fortran,ada,go,lto --enable-plugin --enable-initfini-array --enable-java-awt=gtk --disable-dssi --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre --enable-libgcj-multifile --enable-java-maintainer-mode --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --disable-libjava-multilib --with-ppl --with-cloog --with-tune=generic --with-arch=i686 --build=i686-redhat-linux
Thread model: posix
gcc version 4.7.2 20120921 (Red Hat 4.7.2-2) (GCC)
COLLECT_GCC_OPTIONS='-o' 'test_define' '-v' '-mtune=generic' '-march=i686'
 /usr/libexec/gcc/i686-redhat-linux/4.7.2/cc1 -quiet -v test_define.c -quiet -dumpbase test_define.c -mtune=generic -march=i686 -auxbase test_define -version -o /tmp/ccRMluE4.s   //这里cc1是gcc的编译器,生成临时文件/tmp/ccRMluE4.s
GNU C (GCC) version 4.7.2 20120921 (Red Hat 4.7.2-2) (i686-redhat-linux)
        compiled by GNU C version 4.7.2 20120921 (Red Hat 4.7.2-2), GMP version 5.0.2, MPFR version 3.1.0, MPC version 0.9
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "/usr/lib/gcc/i686-redhat-linux/4.7.2/include-fixed"
ignoring nonexistent directory "/usr/lib/gcc/i686-redhat-linux/4.7.2/../../../../i686-redhat-linux/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/i686-redhat-linux/4.7.2/include
 /usr/local/include
 /usr/include
End of search list.
GNU C (GCC) version 4.7.2 20120921 (Red Hat 4.7.2-2) (i686-redhat-linux)
        compiled by GNU C version 4.7.2 20120921 (Red Hat 4.7.2-2), GMP version 5.0.2, MPFR version 3.1.0, MPC version 0.9
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 84b2ac02994b31f7c32f894822050a6a
COLLECT_GCC_OPTIONS='-o' 'test_define' '-v' '-mtune=generic' '-march=i686'
 as -v --32 -o /tmp/ccNSHywD.o /tmp/ccRMluE4.s    //as GNU汇编器,生成临时文件/tmp/ccNSHywD.o
GNU assembler version 2.22.52.0.1 (i686-redhat-linux) using BFD version version 2.22.52.0.1-10.fc17 20120131
COMPILER_PATH=/usr/libexec/gcc/i686-redhat-linux/4.7.2/:/usr/libexec/gcc/i686-redhat-linux/4.7.2/:/usr/libexec/gcc/i686-redhat-linux/:/usr/lib/gcc/i686-redhat-linux/4.7.2/:/usr/lib/gcc/i686-redhat-linux/
LIBRARY_PATH=/usr/lib/gcc/i686-redhat-linux/4.7.2/:/usr/lib/gcc/i686-redhat-linux/4.7.2/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-o' 'test_define' '-v' '-mtune=generic' '-march=i686'
 /usr/libexec/gcc/i686-redhat-linux/4.7.2/collect2 --build-id --no-add-needed --eh-frame-hdr --hash-style=gnu -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o test_define /usr/lib/gcc/i686-redhat-linux/4.7.2/../../../crt1.o /usr/lib/gcc/i686-redhat-linux/4.7.2/../../../crti.o /usr/lib/gcc/i686-redhat-linux/4.7.2/crtbegin.o -L/usr/lib/gcc/i686-redhat-linux/4.7.2 -L/usr/lib/gcc/i686-redhat-linux/4.7.2/../../.. /tmp/ccNSHywD.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/i686-redhat-linux/4.7.2/crtend.o /usr/lib/gcc/i686-redhat-linux/4.7.2/../../../crtn.o    //collect2是ld链接器的一个包装,调用ld来完成对目标文件的链接;
[lvjianlin@sw1-dev code]$

4.6 连接过程的控制

C++中的链接控制脚本叫做模块定义文件(Module-definition file),扩展名一般为.def.
Linux链接脚本扩展名: lds,   ld script
默认链接脚本可以使用
ld --verbose来查看,存放在/usr/lib/ldscripts/下,


ld链接标本语法简介

“. = ”设置当前虚拟地址;    那么“.”就表示当前地址;
“/DISCARD/ :”被丢弃的段;

命令语句一般的格式是由一个关键字和紧跟其后的参数所组成。

命令语句
说明
ENTRY(symbol)
指定符号为入口地址,即进程执行的第一条用户空间的指令在进程地址空间的地址。
STARTUP(filename)
将文件filename作为连接过程中的第一个输入文件;
SEARCH_DIR(path)
将路径path加入到ld链接器的库查找目录,“-Lpath”
INPUT(file, file)
将指定文件作为链接过程中的输入文件;
INCLUDE filename

PROVIDE(symbol)
在连接脚本中定义某个符号

最复杂的就是SECTIONS段了,

*(.data) 所有输入文件的.data段;*为通配符,还可以使用?、 []等规则;
[a-z]*(.text*[A-Z]),表示输入文件中以小写字母a-z开头的文件中所有段名以.text开头,并且以大写字符A-Z结尾的段。

BFD库(binary file descriptor library) 

PAE : physical address extension

由于可执行文件在装载时实际上是被映射的虚拟空间,所以可执行文件很多时候被叫做映射文件(Image)。

6.4.1 ELF文件链接视图和执行视图
内核关心段与装载有关的内容,不关心其段的实际内容;

为了避免段到内核的映射时产生的内存空间浪费,
ELF可执行文件引入了“segment”概念,一个segment包含一个或多个类似的section;segment是从装载的角度来划分ELF各个段;
从链接角度看,ELF文件是按 section存储的;

readelf有不同的命令来查看segment和section:

[lvjianlin@sw1-dev code]$ readelf  -l test_define

Elf file type is EXEC (Executable file)
Entry point 0x8048300
There are 8 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  PHDR           0x000034 0x08048034 0x08048034 0x00100 0x00100 R E 0x4
  INTERP         0x000134 0x08048134 0x08048134 0x00013 0x00013 R   0x1
      [Requesting program interpreter: /lib/ld-linux.so.2]
  LOAD           0x000000 0x08048000 0x08048000 0x00614 0x00614 R E 0x1000
  LOAD           0x000614 0x08049614 0x08049614 0x00114 0x00118 RW  0x1000
  DYNAMIC        0x000620 0x08049620 0x08049620 0x000e8 0x000e8 RW  0x4
  NOTE           0x000148 0x08048148 0x08048148 0x00044 0x00044 R   0x4
  GNU_EH_FRAME   0x000538 0x08048538 0x08048538 0x0002c 0x0002c R   0x4
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x4

 Section to Segment mapping:
  Segment Sections...
   00     
   01     .interp
   02     .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn .rel.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame
   03     .init_array .fini_array .jcr .dynamic .got .got.plt .data .bss
   04     .dynamic
   05     .note.ABI-tag .note.gnu.build-id
   06     .eh_frame_hdr
   07     
[lvjianlin@sw1-dev code]$
[lvjianlin@sw1-dev code]$ readelf -S test_define
There are 30 section headers, starting at offset 0x85c:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .interp           PROGBITS        08048134 000134 000013 00   A  0   0  1
  [ 2] .note.ABI-tag     NOTE            08048148 000148 000020 00   A  0   0  4
  [ 3] .note.gnu.build-i NOTE            08048168 000168 000024 00   A  0   0  4
  [ 4] .gnu.hash         GNU_HASH        0804818c 00018c 000020 04   A  5   0  4
  [ 5] .dynsym           DYNSYM          080481ac 0001ac 000050 10   A  6   1  4
  [ 6] .dynstr           STRTAB          080481fc 0001fc 00004c 00   A  0   0  1
  [ 7] .gnu.version      VERSYM          08048248 000248 00000a 02   A  5   0  2
  [ 8] .gnu.version_r    VERNEED         08048254 000254 000020 00   A  6   1  4
  [ 9] .rel.dyn          REL             08048274 000274 000008 08   A  5   0  4
  [10] .rel.plt          REL             0804827c 00027c 000018 08   A  5  12  4
  [11] .init             PROGBITS        08048294 000294 000023 00  AX  0   0  4
  [12] .plt              PROGBITS        080482c0 0002c0 000040 04  AX  0   0 16
  [13] .text             PROGBITS        08048300 000300 0001c4 00  AX  0   0 16
  [14] .fini             PROGBITS        080484c4 0004c4 000014 00  AX  0   0  4
  [15] .rodata           PROGBITS        080484d8 0004d8 00005e 00   A  0   0  4
  [16] .eh_frame_hdr     PROGBITS        08048538 000538 00002c 00   A  0   0  4
  [17] .eh_frame         PROGBITS        08048564 000564 0000b0 00   A  0   0  4
  [18] .init_array       INIT_ARRAY      08049614 000614 000004 00  WA  0   0  4
  [19] .fini_array       FINI_ARRAY      08049618 000618 000004 00  WA  0   0  4
  [20] .jcr              PROGBITS        0804961c 00061c 000004 00  WA  0   0  4
  [21] .dynamic          DYNAMIC         08049620 000620 0000e8 08  WA  6   0  4
  [22] .got              PROGBITS        08049708 000708 000004 04  WA  0   0  4
  [23] .got.plt          PROGBITS        0804970c 00070c 000018 04  WA  0   0  4
  [24] .data             PROGBITS        08049724 000724 000004 00  WA  0   0  4
  [25] .bss              NOBITS          08049728 000728 000004 00  WA  0   0  4
  [26] .comment          PROGBITS        00000000 000728 00002c 01  MS  0   0  1
  [27] .shstrtab         STRTAB          00000000 000754 000106 00      0   0  1
  [28] .symtab           SYMTAB          00000000 000d0c 000420 10     29  44  4
  [29] .strtab           STRTAB          00000000 00112c 000258 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

ELF可执行文件/共享文件中, 描述segment的结构叫做程序头表(Program Header Table),
目标文件不需要被装载,所以没有程序头表;

.bss段合并到了.data中,这就导致了FileSiz MemSiz这个两个值有不一致的情况;

[lvjianlin@sw1-dev code]$ cat /proc/self/maps
08048000-08053000 r-xp 00000000 fd:01 144526     /usr/bin/cat
08053000-08054000 r--p 0000a000 fd:01 144526     /usr/bin/cat
08054000-08055000 rw-p 0000b000 fd:01 144526     /usr/bin/cat
0911f000-09140000 rw-p 00000000 00:00 0          [heap]
4a2bb000-4a2da000 r-xp 00000000 fd:01 159520     /usr/lib/ld-2.15.so
4a2da000-4a2db000 r--p 0001e000 fd:01 159520     /usr/lib/ld-2.15.so
4a2db000-4a2dc000 rw-p 0001f000 fd:01 159520     /usr/lib/ld-2.15.so
4a2de000-4a489000 r-xp 00000000 fd:01 168658     /usr/lib/libc-2.15.so
4a489000-4a48a000 ---p 001ab000 fd:01 168658     /usr/lib/libc-2.15.so
4a48a000-4a48c000 r--p 001ab000 fd:01 168658     /usr/lib/libc-2.15.so
4a48c000-4a48d000 rw-p 001ad000 fd:01 168658     /usr/lib/libc-2.15.so
4a48d000-4a490000 rw-p 00000000 00:00 0
b7585000-b7785000 r--p 00000000 fd:01 168630     /usr/lib/locale/locale-archive
b7785000-b7786000 rw-p 00000000 00:00 0
b779a000-b779b000 rw-p 00000000 00:00 0
b779b000-b779c000 r-xp 00000000 00:00 0          [vdso]
bfa0a000-bfa2b000 rw-p 00000000 00:00 0          [stack]
[lvjianlin@sw1-dev code]$
第三列表示偏移,表示VMA对应的segment在映像文件中的偏移;第四列是映像文件所在设备的主设备/次设备号;第五列表示映像文件的节点号。

head,stack主次设备号为0,没有映射到文件,这种VMA叫做匿名虚拟内存区域(Anonymous virtual memory area)
vdso:用于进程与内核进行通信使用;

动态链接
ELF动态链接文件称为动态共享对象(Dynamic Shared Objects),一般以.so为扩展名;
windows,称为动态链接库(Dynamical Linking Library),以.dll为扩展名;

glibc对应的库为 libc.so;
程序与libc.so之间的链接工作由动态链接器完成;

gcc -fPIC -shared -o lib.so lib.c
-shared产生共享对象,表示使用装载时重定位方法;
一个缺点是指令部分无法在多个进程之间共享, 目的是希望程序共享的指令部分在装载时不需要因为装载地址的改变而改变,所以实现的基本想法是把指令中那些需要被修改的部分分离出来,和数据部分放在一起;

这个技术被称为PIC(Position independent-code);

模块间的数据/函数访问需要用到GOT(Global Offset Table)全局偏移表;


7.3.4 共享模块的全局变量问题
多进程共享全局变量叫做共享数据段;
多个线程访问不同全局变量副本叫做“线程私有存储(Thread Local Storage)”;


数据段地址无关性

7.4 延迟绑定PLT
PLT: procedure Linkage Table;


7.5 动态链接相关结构

7.5.1 “.interp”段
这个是interpret (解释器)的缩写, 保存了动态链接器的路径;

objdump -s test_define > test_define.dump-1

cat test_define.dump-1
 
 1
  2 test_define:     file format elf32-i386
  3
  4 Contents of section .interp:
  5  8048134 2f6c6962 2f6c642d 6c696e75 782e736f  /lib/ld-linux.so
  6  8048144 2e3200                               .2.
  7 Contents of section .note.ABI-tag:
[lvjianlin@sw1-dev code]$ readelf -l test_define

Elf file type is EXEC (Executable file)
Entry point 0x8048300
There are 8 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  PHDR           0x000034 0x08048034 0x08048034 0x00100 0x00100 R E 0x4
  INTERP         0x000134 0x08048134 0x08048134 0x00013 0x00013 R   0x1
      [Requesting program interpreter: /lib/ld-linux.so.2]

7.5.2  .dynamic段
主要是动态链接器所需要的基本信息,比如依赖哪些共享对象,动态链接符号表的位置,动态链接重定位表的位置,共享对象初始化代码的地址等;


[lvjianlin@sw1-dev code]$ ldd test_define
        linux-gate.so.1 =>  (0xb77de000)    //内核虚拟共享对象,设计linux系统调用和内核
        libc.so.6 => /lib/libc.so.6 (0x4a2de000)
        /lib/ld-linux.so.2 (0x4a2bb000)

7.5.3 动态符号表

为了表示动态链接这些模块之间的符号导入导出关系,ELF专门有一个叫做动态符号表(dynamic symbol table)的段来保存这些信息;

7.5.4 动态链接重定位表
共享对象需要重定位的主要原因是导入符号的存在;

'.rel.dyn'是对数据引用的修正,所修正位置位于“.got”以及数据段;
'.rel.plt'是对函数引用的修正,所修正位置位于‘.got.plt';

动态链接器自举
具有一定条件的启动代码往往被称为自举;bootstrap;


重定位完成后,若共享对象存在 .init段,那么动态链接器就会执行 .init段中的代码,用以实现共享对象特有的初始化过程; 程序退出时执行.finit;

ELF动态链接器是glibc的一部分,它的源代码位于Glibc的elf目录下,实际入口位于sysdeps/i386/dl-machine.h中的__start;
_start调用了elf/rtld.c的_dl_start();

动态链接器本身是静态链接;


7.7 显示运行时链接



LD_LIBRARY_PATH
LD_PRELOAD
LD_DEBUG

LD_TRACE_LOADED_OBJECTS=1 设置该参数时,解释器将在执行程序之前检查必要的共享库,将其载入内存并把它的信息显示出来。

共享库构造和析构函数

"__attribute__((constructor(X)))"   //X表示优先级
"__attribute__((destructor)) "


8.6.5 共享库脚本   
将多个共享库合为一个; 也可以称为动态链接脚本;


Glibc入口函数


229
230 08048300 <_start>:
231 _start():
232  8048300:       31 ed                   xor    %ebp,%ebp    //清零
233  8048302:       5e                      pop    %esi
234  8048303:       89 e1                   mov    %esp,%ecx    //取出argc
235  8048305:       83 e4 f0                and    $0xfffffff0,%esp
236  8048308:       50                      push   %eax
237  8048309:       54                      push   %esp
238  804830a:       52                      push   %edx
239  804830b:       68 c0 84 04 08          push   $0x80484c0
240  8048310:       68 50 84 04 08          push   $0x8048450
241  8048315:       51                      push   %ecx
242  8048316:       56                      push   %esi
243  8048317:       68 00 84 04 08          push   $0x8048400
244  804831c:       e8 cf ff ff ff          call   80482f0 <__libc_start_main@plt>
245  8048321:       f4                      hlt
246  8048322:       66 90                   xchg   %ax,%ax
247


调用__start之前,装载器已经将用户的参数和环境变量压入栈中,


C语言运行时库, CRT;

TLS: Thread Local Storage 线程局部存储

#define error (*__errno_location())
不同线程调用__errno_location返回的地址不同;


11.3.3 线程局部存储实现
定义前面加一个关键字 "__thread"

TEB: thread environment Block 线程环境块


12.2.3 Linux新型系统调用机制
VDSO: virtual Dynamic Shared Library 虚拟动态共享库;


[lvjianlin@sw1-dev code]$ cat /proc/1181/maps
08048000-08049000 r-xp 00000000 fd:02 5146582    /home/lvjianlin/tmp/code/test_define
08049000-0804a000 rw-p 00000000 fd:02 5146582    /home/lvjianlin/tmp/code/test_define
4a2bb000-4a2da000 r-xp 00000000 fd:01 159520     /usr/lib/ld-2.15.so
4a2da000-4a2db000 r--p 0001e000 fd:01 159520     /usr/lib/ld-2.15.so
4a2db000-4a2dc000 rw-p 0001f000 fd:01 159520     /usr/lib/ld-2.15.so
4a2de000-4a489000 r-xp 00000000 fd:01 168658     /usr/lib/libc-2.15.so
4a489000-4a48a000 ---p 001ab000 fd:01 168658     /usr/lib/libc-2.15.so
4a48a000-4a48c000 r--p 001ab000 fd:01 168658     /usr/lib/libc-2.15.so
4a48c000-4a48d000 rw-p 001ad000 fd:01 168658     /usr/lib/libc-2.15.so
4a48d000-4a490000 rw-p 00000000 00:00 0
b773f000-b7740000 rw-p 00000000 00:00 0
b7753000-b7755000 rw-p 00000000 00:00 0
b7755000-b7756000 r-xp 00000000 00:00 0          [vdso]
bfe49000-bfe6a000 rw-p 00000000 00:00 0          [stack]
[lvjianlin@sw1-dev code]$
[lvjianlin@sw1-dev code]$
[lvjianlin@sw1-dev code]$ ldd test_define
        linux-gate.so.1 =>  (0xb77ce000)
        libc.so.6 => /lib/libc.so.6 (0x4a2de000)
        /lib/ld-linux.so.2 (0x4a2bb000)
书上说可以使用如下的命令导出内存镜像,但在本机上操作失败;
dd if=/proc/self/mem of=/tmp/linux-gate.dso bs=4096 skip=XXX(b7755 二进制) count=1

objdump可以从某一个地址开始反汇编;
objdump -d --start-address=0xffffe400 --stop-address=0xffffe408 linux-gate.dso


阅读(4276) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~