ILD

重定向与符号解析
作者:Herbert Yuan 邮箱:yuanjp@hust.edu.cn
发布时间:2017-11-22 站点:Inside Linux Development

本文学习386架构的可重定向目标文件中的重定向条目,以及符号解析。x86重定向类型有2种:

  1. R_386_PC32:指令使用PC相对地址访问对象,所以链接器应该计算PC相对地址,填充到重定向处。

  2. R_386_32:指令使用绝对地址访问对象,所以链接器应该计算绝对地址,填充到重定向处。


1 重定向目标文件与链接

首先有一个源文件a.c,它访问外部定义的变量foo,和外部定义的函数bar()。

1
2
3
4
5
6
7
8
herbert@herbert-pc:/work/code/link/sample2$ cat a.c
extern int foo;
int bar();
 
int function(void)
{
    return foo + bar();
}


编译:

1
herbert@herbert-pc:/work/code/link/sample2$ cc -m32 -c a.c


查看elf信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
herbert@herbert-pc:/work/code/link/sample2$ readelf -a a.o
。。。
 
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 000016 00  AX  0   0  1
  [ 2] .rel.text         REL             00000000 000180 000010 08   I 10   1  4
  [ 3] .data             PROGBITS        00000000 00004a 000000 00  WA  0   0  1
  [ 4] .bss              NOBITS          00000000 00004a 000000 00  WA  0   0  1
  [ 5] .comment          PROGBITS        00000000 00004a 000035 01  MS  0   0  1
  [ 6] .note.GNU-stack   PROGBITS        00000000 00007f 000000 00      0   0  1
  [ 7] .eh_frame         PROGBITS        00000000 000080 000038 00   A  0   0  4
  [ 8] .rel.eh_frame     REL             00000000 000190 000008 08   I 10   7  4
  [ 9] .shstrtab         STRTAB          00000000 000198 000057 00      0   0  1
  [10] .symtab           SYMTAB          00000000 0000b8 0000b0 10     11   8  4
  [11] .strtab           STRTAB          00000000 000168 000016 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)
 
Relocation section '.rel.text' at offset 0x180 contains 2 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
00000007  00000902 R_386_PC32        00000000   bar
0000000e  00000a01 R_386_32          00000000   foo
 
Relocation section '.rel.eh_frame' at offset 0x190 contains 1 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
00000020  00000202 R_386_PC32        00000000   .text
 
Symbol table '.symtab' contains 11 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 00000000     0 FILE    LOCAL  DEFAULT  ABS a.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    6 
     6: 00000000     0 SECTION LOCAL  DEFAULT    7 
     7: 00000000     0 SECTION LOCAL  DEFAULT    5 
     8: 00000000    22 FUNC    GLOBAL DEFAULT    1 function
     9: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND bar
    10: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND foo

可以看到有一个重定向section .rel.text,这是代码段的重定向条目。


添加一个start.c,它定义了变量foo和函数bar(),并且包含入口_start,调用function()。

1
2
3
4
5
6
7
8
9
10
11
12
13
herbert@herbert-pc:/work/code/link/sample2$ cat start.c
int foo = 2;
int bar()
{
    return 3;
}
 
int function();
 
int _start()
{
    return function();
}


编译,并链接:

1
2
herbert@herbert-pc:/work/code/link/sample2$ cc -m32 -c start.c
herbert@herbert-pc:/work/code/link/sample2$ ld -o a.out a.o start.o -melf_i386

注意,编译出的a.out并不能很好的运行,因为它没有退出逻辑,程序会跑飞,这里仅仅是为了演示重定向与符号解析。


2 分析

a.out的elf信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
herbert@herbert-pc:/work/code/link/sample2$ readelf -a a.out
。。。
 
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        08048094 000094 00002d 00  AX  0   0  1
  [ 2] .eh_frame         PROGBITS        080480c4 0000c4 000078 00   A  0   0  4
  [ 3] .data             PROGBITS        0804913c 00013c 000004 00  WA  0   0  4
  [ 4] .comment          PROGBITS        00000000 000140 000034 01  MS  0   0  1
  [ 5] .shstrtab         STRTAB          00000000 00028a 00003a 00      0   0  1
  [ 6] .symtab           SYMTAB          00000000 000174 0000e0 10      7   7  4
  [ 7] .strtab           STRTAB          00000000 000254 000036 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)
 
There are no section groups in this file.
 
Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000000 0x08048000 0x08048000 0x0013c 0x0013c R E 0x1000
  LOAD           0x00013c 0x0804913c 0x0804913c 0x00004 0x00004 RW  0x1000
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x10
 
 Section to Segment mapping:
  Segment Sections...
   00     .text .eh_frame 
   01     .data 
   02     
 
There is no dynamic section in this file.
 
There are no relocations in this file.
 
The decoding of unwind sections for machine type Intel 80386 is not currently supported.
 
Symbol table '.symtab' contains 14 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 08048094     0 SECTION LOCAL  DEFAULT    1 
     2: 080480c4     0 SECTION LOCAL  DEFAULT    2 
     3: 0804913c     0 SECTION LOCAL  DEFAULT    3 
     4: 00000000     0 SECTION LOCAL  DEFAULT    4 
     5: 00000000     0 FILE    LOCAL  DEFAULT  ABS a.c
     6: 00000000     0 FILE    LOCAL  DEFAULT  ABS start.c
     7: 08048094    22 FUNC    GLOBAL DEFAULT    1 function
     8: 080480b4    13 FUNC    GLOBAL DEFAULT    1 _start
     9: 08049140     0 NOTYPE  GLOBAL DEFAULT    3 __bss_start
    10: 0804913c     4 OBJECT  GLOBAL DEFAULT    3 foo
    11: 08049140     0 NOTYPE  GLOBAL DEFAULT    3 _edata
    12: 08049140     0 NOTYPE  GLOBAL DEFAULT    3 _end
    13: 080480aa    10 FUNC    GLOBAL DEFAULT    1 bar

显然,没有重定向信息了,所有的符号已经解析了。


a.o的反汇编信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
herbert@herbert-pc:/work/code/link/sample2$ objdump -d a.o
 
a.o:     file format elf32-i386
 
 
Disassembly of section .text:
 
00000000 <function>:
   0:    55                       push   %ebp
   1:    89 e5                  mov    %esp,%ebp
   3:    83 ec 08                 sub    $0x8,%esp
   6:    e8 fc ff ff ff           call   7 <function+0x7>
   b:    89 c2                  mov    %eax,%edx
   d:    a1 00 00 00 00           mov    0x0,%eax
  12: 01 d0                  add    %edx,%eax
  14: c9                       leave  
  15: c3                       ret


a.out的反汇编信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
herbert@herbert-pc:/work/code/link/sample2$ objdump -d a.out
 
a.out:     file format elf32-i386
 
 
Disassembly of section .text:
 
08048094 <function>:
 8048094:  55                       push   %ebp
 8048095:  89 e5                  mov    %esp,%ebp
 8048097:  83 ec 08                 sub    $0x8,%esp
 804809a:  e8 0b 00 00 00           call   80480aa <bar>
 804809f:  89 c2                  mov    %eax,%edx
 80480a1:  a1 3c 91 04 08           mov    0x804913c,%eax
 80480a6:  01 d0                  add    %edx,%eax
 80480a8:  c9                       leave  
 80480a9:  c3                       ret    
 
080480aa <bar>:
 80480aa:  55                       push   %ebp
 80480ab:  89 e5                  mov    %esp,%ebp
 80480ad:  b8 03 00 00 00           mov    $0x3,%eax
 80480b2:  5d                       pop    %ebp
 80480b3:  c3                       ret    
 
080480b4 <_start>:
 80480b4:  55                       push   %ebp
 80480b5:  89 e5                  mov    %esp,%ebp
 80480b7:  83 ec 08                 sub    $0x8,%esp
 80480ba:  e8 d5 ff ff ff           call   8048094 <function>
 80480bf:  c9                       leave  
 80480c0:  c3                       ret


2.1 bar()的重定向与解析分析

在a.o的反汇编中,调用bar()的指令为:

1
   6:    e8 fc ff ff ff           call   7 <function+0x7>

e8指令是相对PC函数调用指令[5],后面跟着4个字节的相对地址。所以在a.o的重定向条目:

1
00000007  00000902 R_386_PC32        00000000   bar

类型是R_386_PC32,因为call指令的偏移是6,所以重定向要修改的内容的偏移是6 + 1 = 7。

在a.out的反汇编中,偏移值是0xb = 0x80480aa-0x804809f。0x80480aa是bar()函数的地址,0x804809f是call下一条指令的地址,最后的汇编指令为:

1
 804809a:  e8 0b 00 00 00           call   80480aa <bar>


2.2 foo的重定向与解析

a.o中的重定向条目为:

1
0000000e  00000a01 R_386_32          00000000   foo

其偏移是0xe,对应的指令为:

1
   d:    a1 00 00 00 00           mov    0x0,%eax


a.out中,foo符号的绝对地址为:

1
    10: 0804913c     4 OBJECT  GLOBAL DEFAULT    3 foo

所以最后的汇编指令为:

1
 80480a1:  a1 3c 91 04 08           mov    0x804913c,%eax


3 参考

【1】PLT and GOT - the key to code sharing and dynamic libraries.

https://www.technovelty.org/linux/plt-and-got-the-key-to-code-sharing-and-dynamic-libraries.html


【2】https://www.packtpub.com/books/content/understanding-elf-specimen


【3】Resolving Symbols.

http://web.cse.ohio-state.edu/~reeves.92/CSE2421au12/SlidesDay52.pdf


【4】Study of ELF loading and relocs.

http://netwinder.osuosl.org/users/p/patb/public_html/elf_relocs.html


【5】x86 Instruction Set Reference  CALL.

http://x86.renejeschke.de/html/file_module_x86_id_26.html


Copyright © linuxdev.cc 2017-2024. Some Rights Reserved.