Chinaunix首页 | 论坛 | 博客
  • 博客访问: 34513
  • 博文数量: 6
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 42
  • 用 户 组: 普通用户
  • 注册时间: 2015-10-30 14:15
文章分类

全部博文(6)

文章存档

2016年(6)

我的朋友

分类: LINUX

2016-01-03 21:51:23

        静态链接的整个过程分两步,第一步是空间与地址分配,第二步是符号解析与重定位;其中第二步是链接过程的核心,特别是重定位。在重定位过程中,重定位表和符号表起着至关重要的作用,重定位表确定了需要被重定位的地址,符号表决定了被置换成什么值。
文章内容将以下面的 hello.c 程序为例展开

  1. #include <stdio.h>

  2. int foo(int x)
  3. {
  4.         printf("%d\n", x);

  5.         return 0;
  6. }

  7. int main(void)
  8. {
  9.         foo(5);

  10.         return 0;
  11. }
执行命令gcc  -c  hello.c  -o  test.o  生成目标文件 test.o

一、可重定位表
         连接器在处理目标文件时,须要对目标文件中某些部位进行重定位,即代码段和数据段中那些对绝对地址的引用的位置。这些重定位的信息都记录在ELF文件表里面,对于每个须要重定位的代码段和数据段,都会有一个相应的重定位表,例如 .rel.text 表对应.text段。也就是说,重定位表记录了须要被重定位的地址都在相应段的哪些地方。
       
执行命令 readelf -a test.o 可以看到 .text 的重定位表 .rel.text
  1. 重定位节 '.rel.text' 位于偏移量 0x43c 含有 3 个条目:
  2.  Offset                 Info             Type             Sym.Value     Sym. Name
  3. 00000010     00000501   R_386_32        00000000       .rodata
  4. 00000015     00000a02   R_386_PC32    00000000        printf
  5. 00000031     00000902   R_386_PC32    00000000          foo
                                                                                       <图一>
执行 objdump   -dS    test.o 可以得到test.o 的反汇编代码,如下

  1. 00000000 <foo>:
  2.    0:    55     push %ebp
  3.    1:    89 e5     mov %esp,%ebp
  4.    3:    83 ec 18     sub $0x18,%esp
  5.    6:    8b 45 08     mov 0x8(%ebp),%eax
  6.    9:    89 44 24 04     mov %eax,0x4(%esp)
  7.    d:    c7 04 24 00 00 00 00     movl $0x0,(%esp)
  8.   14:    e8 fc ff ff ff     call 15 <foo+0x15>
  9.   19:    b8 00 00 00 00     mov $0x0,%eax
  10.   1e:    c9     leave
  11.   1f:    c3     ret

  12. 00000020 <main>:
  13.   20:    55     push %ebp
  14.   21:    89 e5     mov %esp,%ebp
  15.   23:    83 e4 f0     and $0xfffffff0,%esp
  16.   26:    83 ec 10     sub $0x10,%esp
  17.   29:    c7 04 24 05 00 00 00     movl $0x5,(%esp)
  18.   30:    e8 fc ff ff ff     call 31 <main+0x11>
  19.   35:    b8 00 00 00 00     mov $0x0,%eax
  20.   3a:    c9     leave
  21.   3b:    c3     ret
                                                                                           <图二>
1>  offset 字段解释
       offset 是重定位入口的偏移。例如,在图一中,符号printf的offset值为015,在<图二>,.text便宜地址0x15存储的内容为0xfc ff ff ff 。
2>  info 字段解释
       该字段表示重定位入口的类型和符号。该值的低8位表示重定位入口的类型, 高24位表示重定位入口的符号在符号表重的下标。
        2.1 重定位入口的类型
              
宏定义

重定位修正方法
R_386_32
1
绝对地址修正 S+A
R_386_PC32
2
相对地址修正 S+A-P
                                                                       <表一>
A = 保存在被修正位置的值(例如本例中printf重定位处的值是0xfc ff ff ff)
P = 被修正的位置(相对于段开始的偏移量或者虚拟地址)
S = 符号的实际地址, 即由info的高24位指定的符号的实际地址
          2.2  高24位表示在符号表中的下标

  1. Symbol table '.symtab' contains 12 entries:
  2.    Num:      Value       Size            Type          Bind                 Vis         Ndx     Name
  3.      0:     00000000     0           NOTYPE         LOCAL     DEFAULT     UND
  4.      1:     00000000     0             FILE             LOCAL      DEFAULT     ABS         hello.c
  5.      2:     00000000     0             SECTION     LOCAL     DEFAULT         1
  6.      3:     00000000     0             SECTION     LOCAL     DEFAULT         3
  7.      4:     00000000     0             SECTION     LOCAL     DEFAULT         4
  8.      5:     00000000     0             SECTION     LOCAL     DEFAULT         5
  9.      6:     00000000     0             SECTION     LOCAL     DEFAULT         7
  10.      7:     00000000      0             SECTION     LOCAL     DEFAULT         8
  11.      8:     00000000      0             SECTION     LOCAL     DEFAULT         6
  12.      9:     00000000     32            FUNC          GLOBAL     DEFAULT        1             foo
  13.     10:    0000000         0             NOTYPE     GLOBAL     DEFAULT     UND        printf
  14.     11:    00000020     28             FUNC         GLOBAL     DEFAULT         1          main
                                                                                                                   <图三>
在本例中,符号printf的info值的高24位是0x00000a,对应的十进制是10;由<图三>可知,下标是10的表项对应的符号是printf,由此可验证info的高24位是符号在符号表中的下标。(重定位表中为什么要和符号表相关连呢? 因为重定位表只是能指定什么地方需要被重定位,但需要被置换成什么数值,这个是由符号表决定的)。

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