重定位类型分析(3)

本文详细分析了ELF32中的四种重定位类型:R_386_RELATIVE用于局部变量的执行时重定位,R_386_JMP_SLOT用于函数的执行时重定位,R_386_GOTOFF用于静态变量的链接时重定位,R_386_COPY用于全局变量的执行时重定位。通过实例展示了这些类型的重定位过程及其在程序执行中的作用。
摘要由CSDN通过智能技术生成

本文分析剩下的四种类型R_386_COPY,R_386_JMP_SLOT,R_386_RELATIVE,R_386_GOTOFF

R_386_RELATIVE 8 word32 B + A
R_386_JMP_SLOT 7 word32 S
R_386_GOTOFF 9 word32 S + A - GOT
R_386_COPY 5 none none


>>>>>>>>>>>>R_386_RELATIVE 用于局部变量,执行时重定位

查看1.c.txt中1.so的readelf

  000013c8  00008 R_386_RELATIVE      
  000013cc  00008 R_386_RELATIVE 
   
offset 00013c8 是地址,相对于1.so加载地址,显然是在.data节中,没有符号名,那他们是什么呢?


  [ 9] .data             PROGBITS        000013c8 0003c8 000008 00  WA  0   0  4

[root@proxy ~/3]# objdump -sj .data 1.so

1.so:     file format elf32-i386

Contents of section .data:
 13c8 b4030000 c2030000                    ........

值分别是03b4和03c2,应该是位于.rodata中

[root@proxy ~/3]# objdump -sj .rodata 1.so

1.so:     file format elf32-i386

Contents of section .rodata:
 03b4 68656c6c 6f20576f 726c6421 0a006162  hello World!..ab
 03c4 6300                                 c.      
 
果然是的.

R_386_RELATIVE 8 word32 B + A,使用加载地址+Offset处值来重定位


验证:由于是执行时连接,需要启用gdb来调试看看
[root@proxy ~/3]# ldd 4
        1.so => /usr/lib/1.so (0x4002a000)
        libc.so.6 => /lib/i686/libc.so.6 (0x4002c000)
        /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

因此
  000013c8  00008 R_386_RELATIVE      
  000013cc  00008 R_386_RELATIVE
加载后的地址为0x4002b3c8,0x4002b3cc

[root@proxy ~/3]# cp 1.so /usr/lib
cp: overwrite `/usr/lib/1.so'? y
[root@proxy ~/3]# gdb -q ./4
(gdb) b main
Breakpoint 1 at 0x8048596
(gdb) r
Starting program: /root/3/./4

Breakpoint 1, 0x08048596 in main ()
(gdb) x/w 0x4002b3c8
0x4002b3c8 <s>: 0x4002a3b4
(gdb) x/w 0x4002b3cc
0x4002b3cc <t>: 0x4002a3c2
(gdb)

Contents of section .data:
 13c8 b4030000 c2030000                    ........
分别加上0x4002a000就是上面的结果

 

 

>>>>>>>>>>>R_386_JMP_SLOT 用于函数,执行时重定位

这个简单,应该修正为符号的实际值S(例如函数f的地址)

 

 

>>>>>>>>>>>R_386_GOTOFF 用于静态变量,链接是重定位

1.o中 .rel.text节中的该类型条目有:

  00000018  00309 R_386_GOTOFF          00000000  .data

  该条目的意思就是GOT生成后,并在GOT表中为该静态变量分配条目后,将该条目在GOT表中的index写入到.text节中偏移地址为0000 0018 的地方。

 

1.o中.text节中的代码
  16:   ff b3 00 00 00 00       pushl  0x0(%ebx)

相应的汇编代码:

    pushl   s@GOTOFF(%ebx )

通过链接成.so库以后生成的结果:       
生成1.so中

    372:   ff b3 f8 ff ff ff       pushl  0xfffffff8(%ebx)
 修正值为0xfffffff8,即-8,即got-8处.

 

[root@proxy ~/3]# objdump -sj .data 1.so

1.so:     file format elf32-i386

Contents of section .data:
 13c8 b4030000 c2030000                    ........     

 

即s的值为03b4,指向.rodata


[root@proxy ~/3]# objdump -sj .rodata 1.so

1.so:     file format elf32-i386

Contents of section .rodata:
 03b4 68656c6c 6f20576f 726c6421 0a006162  hello World!..ab
 03c4 6300                                 c.     

 

所以R_386_GOTOFF的修正方式是:将符号地址和GOT地址差值加上Offset处值存入Offset处.//S + A - GOT

 

 

>>>>>R_386_COPY,用于全局变量,执行时重定位

4中.rel.dyn节中有如下条目:

  08049748  00105 R_386_COPY            08049748  t 

该条目的意思是将.text节中08049748地方的内容修改为动态节符号节.dynsym中相应符号地址中内容。

  [22] .bss              NOBITS          08049748 000748 00001c 00  WA  0   0  4 //在.bss中1.so中

 

在.dynsym节中有如下条目:
    16: 000013cc     4 OBJECT  GLOBAL DEFAULT    9 t


加载地址0x4002a00,所以t的值是0x4002b3cc     

 

abcabc[root@proxy ~/3]# gdb -q ./4
(gdb) b main
Breakpoint 1 at 0x8048596
(gdb) r
Starting program: /root/3/./4

Breakpoint 1, 0x08048596 in main ()
(gdb) x /w 0x08049748 //查4中t的值
0x8049748 <t>:  0x4002a3c2
(gdb) x /w 0x4002b3cc //查1.so中t的值
0x4002b3cc <t>: 0x4002a3c2
(gdb)  

两个值相等

所以R_386_COPY的修正方式是:将解析到的符号地址处的值(大小由size决定)复制到Offset处。

这实现了每个可执行文件都有独立的全局变量,而不互相干扰。

可以发现重定位目标文件有.symtab表,这个表是必须的,虽然可以用strip去掉,但是最终连接时会出错
而动态链接库文件和可执行文件有.dynsym和.symtab,.dynsym是必须的,而.symtab不是,可以执行strip命令去掉

附件1

1.c

[root@proxy ~/3]# cat 1.c
#include <stdio.h>

static char *s="hello World!/n";
char *t="abc";

void f()
{
printf(s);
}

void g()
{
printf(t);
}
[root@proxy ~/3]# gcc -fPIC -S 1.c
[root@proxy ~/3]# cat 1.s
        .file   "1.c"
        .version        "01.01"
gcc2_compiled.:
                .section        .rodata
.LC0:
        .string "hello World!/n"
.data
        .align 4
        .type    s,@object
        .size    s,4
s:
        .long   .LC0
.globl t
                .section        .rodata
.LC1:
        .string "abc"
.data
        .align 4
        .type    t,@object
        .size    t,4
t:
        .long   .LC1
.text
        .align 4
.globl f
        .type    f,@function
f:
        pushl   %ebp
        movl    %esp, %ebp
        pushl   %ebx
        subl    $4, %esp
        call    .L3
.L3:
        popl    %ebx
        addl    $_GLOBAL_OFFSET_TABLE_+[.-.L3], %ebx
        subl    $12, %esp
        pushl   s@GOTOFF(%ebx )
        call    printf@PLT
        addl    $16, %esp
        movl    -4(%ebp), %ebx
        leave
        ret
.Lfe1:
        .size    f,.Lfe1-f
        .align 4
.globl g
        .type    g,@function
g:
        pushl   %ebp
        movl    %esp, %ebp
        pushl   %ebx
        subl    $4, %esp
        call    .L5
.L5:
        popl    %ebx
        addl    $_GLOBAL_OFFSET_TABLE_+[.-.L5], %ebx
        subl    $12, %esp
        movl    t@GOT(%ebx ), %eax
        pushl   (%eax)
        call    printf@PLT
        addl    $16, %esp
        movl    -4(%ebp), %ebx
        leave
        ret
.Lfe2:
        .size    g,.Lfe2-g
        .ident  "GCC: (GNU) 2.96 20000731 (Red Hat Linux 7.1 2.96-98)"
[root@proxy ~/3]# gcc -fPIC -c 1.c -o 1.o
[root@proxy ~/3]# ld -shared 1.o -o 1.so
[root@proxy ~/3]# objdump -dj .text 1.o

1.o:     file format elf32-i386

Disassembly of section .text:

00000000 <f>:
   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 <f+0xc>
   c:   5b                      pop    %ebx
   d:   81 c3 03 00 00 00       add    $0x3,%ebx
  13:   83 ec 0c                sub    $0xc,%esp
  16:   ff b3 00 00 00 00       pushl  0x0(%ebx)
  1c:   e8 fc ff ff ff          call   1d <f+0x1d>
  21:   83 c4 10                add    $0x10,%esp
  24:   8b 5d fc                mov    0xfffffffc(%ebp),%ebx
  27:   c9                      leave 
  28:   c3                      ret   
  29:   8d 76 00                lea    0x0(%esi),%esi

0000002c <g>:
  2c:   55                      push   %ebp
  2d:   89 e5                   mov    %esp,%ebp
  2f:   53                      push   %ebx
  30:   83 ec 04                sub    $0x4,%esp
  33:   e8 00 00 00 00          call   38 <g+0xc>
  38:   5b                      pop    %ebx
  39:   81 c3 03 00 00 00       add    $0x3,%ebx
  3f:   83 ec 0c                sub    $0xc,%esp
  42:   8b 83 00 00 00 00       mov    0x0(%ebx),%eax
  48:   ff 30                   pushl  (%eax)
  4a:   e8 fc ff ff ff          call   4b <g+0x1f>
  4f:   83 c4 10                add    $0x10,%esp
  52:   8b 5d fc                mov    0xfffffffc(%ebp),%ebx
  55:   c9                      leave 
  56:   c3                      ret   
  57:   90                      nop   
[root@proxy ~/3]# readelf -a 1.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:          328 (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)
 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值