Chinaunix首页 | 论坛 | 博客
  • 博客访问: 59357
  • 博文数量: 27
  • 博客积分: 2000
  • 博客等级: 大尉
  • 技术积分: 300
  • 用 户 组: 普通用户
  • 注册时间: 2009-04-24 17:31
文章分类
文章存档

2011年(1)

2010年(8)

2009年(18)

我的朋友

分类: LINUX

2009-06-28 13:22:19

3.5节的补充说明和例子:

 

静态全局变量的重定位过程和在文件中的存放位置。

内存变量有
2个基本属性:变量的地址 变量的内容。编译器+汇编器 加工产出的文件包含1系列汇编语句代码, 包括 .text + .data +
.bss,但有很多不确定的地址:主要有2部分地址需要确定:1。符号(即变量/函数名字)本身的偏移量是多少  2。符号里的内容如果是个地址,要确定该地址是多少。因此编译器把一些中间结果记录在一些辅助的section里。让连接器继续重定位,连接器如果还是定位不出具体地址,就把中间结果记录下来,让加载器继续重定位。

 

1.so 里的汇编指令地址,都是记录的偏移量。.exe里的汇编指令地址,基本都是确定的虚拟内存地址,需要重定位的内容很少。

 

2。符号本身(在文件内)的偏移量。在编译/连接时就可以计算,因此直接记录在.symtab里,连接时要继续修改.symtab。编译器(汇编器)和连接器主要使用.symtab记录符号偏移量。动态加载器所需要确定的符号,很多都放在到.dynsym里,.symtab不那么重要了。

 

3.text.data里的符号里所包含的"内容"可能需要重定位计算。如果内容是1个地址,那么就是需要重定位的。因此分别会产生 .rel.text .rel.dataxxx section,表示说:嗨!注意,这些符号里的内容是地址,要进行重定位计算。如果符号里的“内容”是1个常量,则一般连接器ld直接能计算出来,不必要重定位。

 

4。加载运行时,.data 内容先重定位(main()之前),然后再对 .text 内容再重定位。

 

 

5。实际例子:

思路:(1)选取1个符号,先研究.o里的重定位项(供连接器使用),然后再研究.so里的重定位项(供动态加载器使用)

      2)在.o里面,先找符号表,找到符号所在的section和偏移量 --> 再研究符号对应的重定位表项目

      3)研究的工具是:objdumpreadelf.

 

 

例子:我们研究全局静态指针变量:static char *p222 = "aaaaaaaaaa";

 

[elf@redhat elf]# more bbb.c

int a111 = 15;

char *g111;

char *g222 = "456";

static char *p111;

static char *p222 = "aaaaaaaaaa";

static char *p333;

static char *p444 = "bbbb";

 

int foo2()

{

    p333 = "cc";

    char *p555 = "dd";

    static char *p666= "123";

 

    p111 = (char *)malloc(10);

 

    strcpy(p111, "13579");

}

 

() 首先编译出位置无关代码:bbb.o

[elf@redhat elf]# gcc -fPIC -c bbb.c

 

(1)先在符号表里找到p222

[elf@redhat elf]# readelf -a bbb.o

Symbol table '.symtab' contains 21 entries:    # 符号表记录所有符号本身的偏移值

   Num:    Value  Size Type    Bind   Vis      Ndx Name               

     7: 00000004     4 OBJECT  LOCAL  DEFAULT    6 p222        # p222 所在节号为 6(.data.rel.local section),节内偏移量为4

 

(2)察看p222对应的重定位项目:

[elf@redhat elf]# readelf -a bbb.o

Relocation section '.rel.data.rel.local' at offset 0x558 contains 4 entries:

 Offset     Info    Type            Sym.Value  Sym. Name

00000004  00000501 R_386_32          00000000   .rodata        # 表示.rel.data.rel节中 偏移4处的内容是一个地址,此地址.rodata相关,目前不能最终确定,需要继续重定位。

 

# 编译器产生此重定位项,表示自己不能确定出p222的最终地址,让连接器使用此信息继续完成重定位,一棒接一棒接力完成最终地址的重定

位。

 

Section Headers:

  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al

  [ 0]                   NULL            00000000 000000 000000 00      0   0  0

  [ 1] .text             PROGBITS        00000000 000034 000058 00  AX  0   0  4

  [ 2] .rel.text         REL             00000000 000510 000048 08     11   1  4

  [ 3] .data             PROGBITS        00000000 00008c 000004 00  WA  0   0  4

  [ 4] .bss              NOBITS          00000000 000090 000008 00  WA  0   0  4

  [ 5] .rodata           PROGBITS        00000000 000090 000024 00   A  0   0  1

  [ 6] .data.rel.local   PROGBITS        00000000 0000b4 000010 00  WA  0   0  4

  [ 7] .rel.data.rel.loc REL             00000000 000558 000020 08     11   6  4

  [ 8] .note.GNU-stack   NOTE            00000000 0000c4 000000 00      0   0  1

  [ 9] .comment          PROGBITS        00000000 0000c4 000031 00      0   0  1

  [10] .shstrtab         STRTAB          00000000 0000f5 000065 00      0   0  1

  [11] .symtab           SYMTAB          00000000 000364 000150 10     12   e  4

  [12] .strtab           STRTAB          00000000 0004b4 00005a 00      0   0  1


# .rel.data.rel.loc需要重定位的符号所在的符号表为11(.symtab section), 需要重定位的节号为6(.data.rel.local section)
 

 

(3)察看各个节包含的实际内容

[elf@redhat elf]# objdump -s bbb.o

Contents of section .data:

 0000 0f000000                             ....         

Contents of section .rodata:

 0000 34353600 61616161 61616161 61610062  456.aaaaaaaaaa.b

 0010 62626200 31323300 63630064 64003133  bbb.123.cc.dd.13

 0020 35373900                             579.           

Contents of section .data.rel.local:

 0000 00000000 04000000 0f000000 14000000  ................   

 

 

# 可以看到:

全局普通变量int a111=15=0f 直接存放在.data里。以后的连接过程中: .data section的位置会发生改变,int a111变量本身的地址需要随之重定位修改,但a111里面包含的内容(0f)是不会改变的。

 

.data.rel.local section里,存放4个指针变量:*g222 = 00; *p222 = 04; *p444 = 0f; *p666 = 14;  指针变量里面包含的内容是1地址/偏移量4个指针变量 里面目前包含的内容是 指向.rodata里的偏移量,分别对应各自的字符串值。比如:P222包含的内容为04,指向对应的.rodata里的"aaaaaaaaaa"

 

4个指针变量只是 临时存放在:.data.rel.local等待重定位处理。以后的连接过程中: .data section的位置会发生改变,4个指针变量本身的地址需要随之重定位修改;而且由于.rodata section的位置也会发生改变,指针变量里面包含的偏移量是指向.rodata的,也要进行重定位计算,并最终把4个指针变量存放在.data里面。

char *g222 = "456";

static char *p222 = "aaaaaaaaaa";

static char *p444 = "bbbb";

static char *p666= "123";

 

 

() 然后连接为bbb.so

[elf@redhat elf]# gcc -shared -o bbb.so ./bbb.o

 

(1)先在符号表找到p222

[elf@redhat elf]# readelf -a bbb.so

Symbol table '.symtab' contains 64 entries:

   Num:    Value  Size Type    Bind   Vis      Ndx Name

    42: 00001808     4 OBJECT  LOCAL  DEFAULT   14 p222        # p222 所在节号为 14(.data section),节内偏移量为 1808; 而且.dynsym里没有p222符号,说明静态变量不记录在.dynsym里,.dynsym只记录全局符号。

 

(2)重定位已经完成,不需要动态加载器继续重定位了,所以没有相关的重定位项了。

 

(3)察看各个节包含的实际内容

[elf@redhat elf]# objdump -s bbb.o

Contents of section .rodata:

 07cf 34353600 61616161 61616161 61610062  456.aaaaaaaaaa.b

 07df 62626200 31323300 63630064 64003133  bbb.123.cc.dd.13

 07ef 35373900                             579.            

Contents of section .data:

 17f8 f8170000 e0180000 0f000000 cf070000  ................

 1808 d3070000 de070000 e3070000           ............     # 偏移1808处的内容是000007d3

 

 

# 可以看到:程序连接后,.rodata 位置发生改变,开始地址变为:07cf.data 位置发生改变,开始地址变为:17f8p222指针变量本身的地址被重定位计算为:1808P222包含的内容原来为04,现在重定位计算为:07d3,仍然指向对应的.rodata里的"aaaaaaaaaa";且P222被存放.data里。.data.rel.local section 已经不存在了。

 

 

====================================================================

实际输出:

 

[elf@redhat elf]# readelf -a bbb.o

ELF Header:

  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00

  Class:                             ELF32

  Data:                              2's complement, little endian

  Version:                           1 (current)

  OS/ABI:                            UNIX - System V

  ABI Version:                       0

  Type:                              REL (Relocatable file)

  Machine:                           Intel 80386

  Version:                           0x1

  Entry point address:               0x0

  Start of program headers:          0 (bytes into file)

  Start of section headers:          348 (bytes into file)

  Flags:                             0x0

  Size of this header:               52 (bytes)

  Size of program headers:           0 (bytes)

  Number of program headers:         0

  Size of section headers:           40 (bytes)

  Number of section headers:         13

  Section header string table index: 10

 

Section Headers:

  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al

  [ 0]                   NULL            00000000 000000 000000 00      0   0  0

  [ 1] .text             PROGBITS        00000000 000034 000058 00  AX  0   0  4

  [ 2] .rel.text         REL             00000000 000510 000048 08     11   1  4

  [ 3] .data             PROGBITS        00000000 00008c 000004 00  WA  0   0  4

  [ 4] .bss              NOBITS          00000000 000090 000008 00  WA  0   0  4

  [ 5] .rodata           PROGBITS        00000000 000090 000024 00   A  0   0  1

  [ 6] .data.rel.local   PROGBITS        00000000 0000b4 000010 00  WA  0   0  4

  [ 7] .rel.data.rel.loc REL             00000000 000558 000020 08     11   6  4

  [ 8] .note.GNU-stack   NOTE            00000000 0000c4 000000 00      0   0  1

  [ 9] .comment          PROGBITS        00000000 0000c4 000031 00      0   0  1

  [10] .shstrtab         STRTAB          00000000 0000f5 000065 00      0   0  1

  [11] .symtab           SYMTAB          00000000 000364 000150 10     12   e  4

  [12] .strtab           STRTAB          00000000 0004b4 00005a 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)

 

There are no program headers in this file.

 

Relocation section '.rel.text' at offset 0x510 contains 9 entries:

 Offset     Info    Type            Sym.Value  Sym. Name

0000000f  0000110a R_386_GOTPC       00000000   _GLOBAL_OFFSET_TABLE_

00000015  00000509 R_386_GOTOFF      00000000   .rodata

0000001b  00000409 R_386_GOTOFF      00000000   .bss

00000021  00000509 R_386_GOTOFF      00000000   .rodata

0000002e  00001204 R_386_PLT32       00000000   malloc

00000037  00000409 R_386_GOTOFF      00000000   .bss

00000040  00000509 R_386_GOTOFF      00000000   .rodata

00000047  00000409 R_386_GOTOFF      00000000   .bss

0000004c  00001304 R_386_PLT32       00000000   strcpy

 

Relocation section '.rel.data.rel.local' at offset 0x558 contains 4 entries:

 Offset     Info    Type            Sym.Value  Sym. Name

00000000  00000501 R_386_32          00000000   .rodata

00000004  00000501 R_386_32          00000000   .rodata

00000008  00000501 R_386_32          00000000   .rodata

0000000c  00000501 R_386_32          00000000   .rodata

 

There are no unwind sections in this file.

 

Symbol table '.symtab' contains 21 entries:                   # 符号表记录所有符号本身的偏移

   Num:    Value  Size Type    Bind   Vis      Ndx Name

     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND

     1: 00000000     0 FILE    LOCAL  DEFAULT  ABS bbb.c

     2: 00000000     0 SECTION LOCAL  DEFAULT    1

     3: 00000000     0 SECTION LOCAL  DEFAULT    3

     4: 00000000     0 SECTION LOCAL  DEFAULT    4

     5: 00000000     0 SECTION LOCAL  DEFAULT    5

     6: 00000000     0 SECTION LOCAL  DEFAULT    6

     7: 00000004     4 OBJECT  LOCAL  DEFAULT    6 p222       # 比如 p222 所在section 6(.data.rel.local),偏移为 4

     8: 00000008     4 OBJECT  LOCAL  DEFAULT    6 p444       # 比如 p444 所在section 6(.data.rel.local),偏移为 8

     9: 0000000c     4 OBJECT  LOCAL  DEFAULT    6 p666.0

    10: 00000004     4 OBJECT  LOCAL  DEFAULT    4 p333       # 比如 p333 所在section 4(.bss),偏移为 4

    11: 00000000     4 OBJECT  LOCAL  DEFAULT    4 p111

    12: 00000000     0 SECTION LOCAL  DEFAULT    8

    13: 00000000     0 SECTION LOCAL  DEFAULT    9

    14: 00000000     4 OBJECT  GLOBAL DEFAULT    3 a111       # 比如 a111 所在section 3(.data),偏移为 4,因为a111个普通全局变量,而不是全局指针型变量,所以直接放在.data

    15: 00000000     4 OBJECT  GLOBAL DEFAULT    6 g222

    16: 00000000    88 FUNC    GLOBAL DEFAULT    1 foo2

    17: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND _GLOBAL_OFFSET_TABLE_

    18: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND malloc

    19: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND strcpy

    20: 00000004     4 OBJECT  GLOBAL DEFAULT  COM g111

 

No version information found in this file.

 

 

[elf@redhat elf]# objdump -s bbb.o

 

bbb.o:     file format elf32-i386

 

Contents of section .text:

 0000 5589e553 83ec04e8 00000000 5b81c303  U..S........[...

 0010 0000008d 83180000 00898304 0000008d  ................

 0020 831b0000 008945f8 83ec0c6a 0ae8fcff  ......E....j....

 0030 ffff83c4 10898300 00000083 ec088d83  ................

 0040 1e000000 50ffb300 000000e8 fcffffff  ....P...........

 0050 83c4108b 5dfcc9c3                    ....]...       

Contents of section .data:

 0000 0f000000                             ....           

Contents of section .rodata:

 0000 34353600 61616161 61616161 61610062  456.aaaaaaaaaa.b

 0010 62626200 31323300 63630064 64003133  bbb.123.cc.dd.13

 0020 35373900                             579.           

Contents of section .data.rel.local:

 0000 00000000 04000000 0f000000 14000000  ................

Contents of section .note.GNU-stack:

Contents of section .comment:

 0000 00474343 3a202847 4e552920 332e322e  .GCC: (GNU) 3.2.

 0010 33203230 30333035 30322028 54757262  3 20030502 (Turb

 0020 6f4c696e 75782033 2e322e33 2d313029  oLinux 3.2.3-10)

 0030 00                                   .              

 

 

[elf@redhat elf]# objdump -d bbb.o

 

bbb.o:     file format elf32-i386

 

Disassembly of section .text:

 

00000000 :

   0:   55                      push   %ebp

   1:   89 e5                   mov    %esp,%ebp

   3:   53                      push   %ebx

   4:   83 ec 04                sub    $0x4,%esp

   7:   e8 00 00 00 00          call   c

   c:   5b                      pop    %ebx

   d:   81 c3 03 00 00 00       add    $0x3,%ebx

  13:   8d 83 18 00 00 00       lea    0x18(%ebx),%eax

  19:   89 83 04 00 00 00       mov    %eax,0x4(%ebx)

  1f:   8d 83 1b 00 00 00       lea    0x1b(%ebx),%eax

  25:   89 45 f8                mov    %eax,0xfffffff8(%ebp)

  28:   83 ec 0c                sub    $0xc,%esp

  2b:   6a 0a                   push   $0xa

  2d:   e8 fc ff ff ff          call   2e

  32:   83 c4 10                add    $0x10,%esp

  35:   89 83 00 00 00 00       mov    %eax,0x0(%ebx)

  3b:   83 ec 08                sub    $0x8,%esp

  3e:   8d 83 1e 00 00 00       lea    0x1e(%ebx),%eax

  44:   50                      push   %eax

  45:   ff b3 00 00 00 00       pushl  0x0(%ebx)

  4b:   e8 fc ff ff ff          call   4c 4c>

  50:   83 c4 10                add    $0x10,%esp

  53:   8b 5d fc                mov    0xfffffffc(%ebp),%ebx

  56:   c9                      leave 

  57:   c3                      ret   

 

================================================================

================================================================

 

[elf@redhat elf]# readelf -a bbb.so   # 对比一下连接后,同一符号的值有何变化。

 

对比一下,*.o*.so在不同连接阶段的变化。

 

[elf@redhat elf]# objdump -s bbb.so

 

[elf@redhat elf]# objdump -d bbb.so

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