关于-fPIC选项 和 GOT表

http://blog.sina.com.cn/s/blog_54f82cc201011orc.html

加上-fPIC参数后,编译后的文件和没有加这个参数的文件,有什么区别呢?
没有加这个参数的编译后的共享库,也可以使用,它和加了参数后的使用起来
又有什么区别呢?

position independent(位置无关)
relocate(可重定位)

位置无关代码主要是在访问全局变量和全局函数的时候采用了位置无关的重定位方法,
即依赖GOT和PLT来重定位。


普通的重定位方法需要修改代码段,比如偏移地址0x100处需要重定位,loader就修改代码段的0x100处的内容,通过查找重定位信息得到具体的值。 这种方法需要修改代码段的内容,对于动态连接库来说,其初衷是让多个进程共享代码段,若对其进行写操作,就回引起COW,从而失去共享。

-fPIC选项告诉编绎器使用GOT和PLT的方法重定位,GOT是数据段,因此避免了COW,真正实现了共享。
如果不用-fPIC,动态连接库依然可以使用,但其重定位方法为一般方法,必然会引起COW,但也无所谓,除了性能在COW时稍微受些影响,其他也没啥。

GOT 是 data section,是一个 table,除专用的几个 entry,每个 entry的内容可以再执行的时候修改;
PLT 是 text section,是一段一段的 code,执行中不需要修改。


http://www.linuxforum.net/forum/showflat.php?Cat=&Board=cpu&Number=688070&page=&view=&sb=&o=&vc=1



如何得到GOT表

汇编语言片段:
2f7: e8 00 00 00 00        call   2fc <ok+0xc>

 2fc: 5b                    pop    �x

 2fd: 81 c3 b0 10 00 00     add    $0x10b0,�x

这里的2f7中的call 2fc <ok+0xc>和2fc处的pop�x,得到运行时的eip地址,存入ebx寄存器中。

后面的add$0x10b0,�x又是什么用处?如果我们这里假定在内存中的地址是2fc,那加上10b0之后的值是0x13ac了,看在这里是什么呢?

Disassembly of section .got:

000013ac <.got>:

    13ac: 34 13                 xor    $0x13,%al

 ...

可以看出这是一个got节。



-------------------------

一个例子

对于加了-fPIC选项的共享库,如:gcc-shared -fPIC  -o libhello.so hello.c,
其.got.plt section中存放外部函数的地址,.got section中存放全局变量的地址。
.got.plt紧接在.got后面,ebx寄存器存放.got.plt地址,正偏移引用函数地址,负偏移引用数据地址。
对于static变量(不通过GOT表来引用),如static int ss;可以用ss@GOTOFF(�x)来引用(相对于GOT表的偏移)。
// hello.c

#include <stdio.h>

#include <stdlib.h>



int count;

char ch;

struct _s {

    int s1;

    int s2;

} s;



void say_hello()

{

    printf("Hello:%x\n", ++count);

    printf("Hello:%x\n", ++ch);

    printf("Hello:%x\n", ++s.s1);

    printf("Hello:%x\n", ++s.s2);

}
jfo@lab:~/test$ gcc -ggdb -shared -fPIC  -o libhello.so  hello.c



jfo@lab:~/test$ readelf -x.got libhello.so



Hex dump of section '.got':

  0x000016a0 00000000 00000000 00000000 00000000 ................

  0x000016b0 00000000 00000000                   ........



jfo@lab:~/test$ readelf -x.got.plt libhello.so



Hex dump of section '.got.plt':

  0x000016b8 d8150000 00000000 00000000 9e030000 ................

  0x000016c8 ae030000 be030000                   ........



jfo@lab:~/test$ objdump -S -j.plt libhello.so



libhello.so:     file format elf32-i386



Disassembly of section .plt:



00000388 <__gmon_start__@plt-0x10>:

 388:   ff b3 04 00 00 00       pushl  0x4(�x)

 38e:   ff a3 08 00 00 00       jmp    *0x8(�x)

 394:   00 00                   add    %al,(�x)

        ...



00000398 <__gmon_start__@plt>:

 398:   ff a3 0c 00 00 00       jmp    *0xc(�x)

 39e:   68 00 00 00 00          push   $0x0

 3a3:   e9 e0 ff ff ff          jmp    388 <_init+0x30>



000003a8 <printf@plt>:

 3a8:   ff a3 10 00 00 00       jmp    *0x10(�x)

 3ae:   68 08 00 00 00          push   $0x8

 3b3:   e9 d0 ff ff ff          jmp    388 <_init+0x30>



000003b8 <__cxa_finalize@plt>:

 3b8:   ff a3 14 00 00 00       jmp    *0x14(�x)

 3be:   68 10 00 00 00          push   $0x10

 3c3:   e9 c0 ff ff ff          jmp    388 <_init+0x30>





jfo@lab:~/test$ objdump -S -j.text libhello.so

 ...

void say_hello()

{

 48c:   55                      push   �p

 48d:   89 e5                   mov    %esp,�p

 48f:   53                      push   �x

 490:   83 ec 14                sub    $0x14,%esp

 493:   e8 ef ff ff ff          call   487 <__i686.get_pc_thunk.bx>

 498:   81 c3 20 12 00 00       add    $0x1220,�x

    printf("Hello:%x\n", ++count);

 49e:   8b 83 f8 ff ff ff       mov    -0x8(�x),�x

 4a4:   8b 00                   mov    (�x),�x

 4a6:   8d 50 01                lea    0x1(�x),�x

 4a9:   8b 83 f8 ff ff ff       mov    -0x8(�x),�x

 4af:   89 10                   mov    �x,(�x)

 4b1:   8b 83 f8 ff ff ff       mov    -0x8(�x),�x

 4b7:   8b 00                   mov    (�x),�x

 4b9:   89 44 24 04             mov    �x,0x4(%esp)

 4bd:   8d 83 fc ee ff ff       lea    -0x1104(�x),�x

 4c3:   89 04 24                mov    �x,(%esp)

 4c6:   e8 dd fe ff ff          call   3a8 <printf@plt>

    printf("Hello:%x\n", ++ch);

 4cb:   8b 83 f4 ff ff ff       mov    -0xc(�x),�x

 4d1:   0f b6 00                movzbl (�x),�x

 4d4:   8d 50 01                lea    0x1(�x),�x

 4d7:   8b 83 f4 ff ff ff       mov    -0xc(�x),�x

 4dd:   88 10                   mov    %dl,(�x)

 4df:   8b 83 f4 ff ff ff       mov    -0xc(�x),�x

 4e5:   0f b6 00                movzbl (�x),�x

 4e8:   0f be c0                movsbl %al,�x

 4eb:   89 44 24 04             mov    �x,0x4(%esp)

 4ef:   8d 83 fc ee ff ff       lea    -0x1104(�x),�x

 4f5:   89 04 24                mov    �x,(%esp)

 4f8:   e8 ab fe ff ff          call   3a8 <printf@plt>

    printf("Hello:%x\n", ++s.s1);

 4fd:   8b 83 e8 ff ff ff       mov    -0x18(�x),�x

 503:   8b 00                   mov    (�x),�x

 505:   8d 50 01                lea    0x1(�x),�x

 508:   8b 83 e8 ff ff ff       mov    -0x18(�x),�x

 50e:   89 10                   mov    �x,(�x)

 510:   8b 83 e8 ff ff ff       mov    -0x18(�x),�x

 516:   8b 00                   mov    (�x),�x

 518:   89 44 24 04             mov    �x,0x4(%esp)

 51c:   8d 83 fc ee ff ff       lea    -0x1104(�x),�x

 522:   89 04 24                mov    �x,(%esp)

 525:   e8 7e fe ff ff          call   3a8 <printf@plt>

    printf("Hello:%x\n", ++s.s2);

 52a:   8b 83 e8 ff ff ff       mov    -0x18(�x),�x

 530:   8b 40 04                mov    0x4(�x),�x

 533:   8d 50 01                lea    0x1(�x),�x

 536:   8b 83 e8 ff ff ff       mov    -0x18(�x),�x

 53c:   89 50 04                mov    �x,0x4(�x)

 53f:   8b 83 e8 ff ff ff       mov    -0x18(�x),�x

 545:   8b 40 04                mov    0x4(�x),�x

 548:   89 44 24 04             mov    �x,0x4(%esp)

 54c:   8d 83 fc ee ff ff       lea    -0x1104(�x),�x

 552:   89 04 24                mov    �x,(%esp)

 555:   e8 4e fe ff ff          call   3a8 <printf@plt>

}

 ...







jfo@lab:~/test$ readelf -a libhello.so

 ...



Relocation section '.rel.dyn' at offset 0x308 contains 7 entries:

 Offset     Info    Type            Sym.Value  Sym. Name

000016d0  00000008 R_386_RELATIVE

000016a0  00000806 R_386_GLOB_DAT    000016dc   s                    //offset -0x18(ebx)

000016a4  00000106 R_386_GLOB_DAT    00000000   __gmon_start__       //offset -0x14(ebx)

000016a8  00000206 R_386_GLOB_DAT    00000000   _Jv_RegisterClasses  //offset -0x10(ebx)

000016ac  00000d06 R_386_GLOB_DAT    000016e4   ch                   //offset -0xc(ebx)

000016b0  00000906 R_386_GLOB_DAT    000016e8   count                //offset -0x8(ebx)

000016b4  00000406 R_386_GLOB_DAT    00000000   __cxa_finalize       //offset -0x4(ebx)

//Offset000016a0、000016ac、000016b0位于.got section

//Sym.Value000016dc、000016e4、000016e8对应.bss段变量的地址



Relocation section '.rel.plt' at offset 0x340 contains 3 entries:

 Offset     Info    Type            Sym.Value  Sym. Name

000016c4  00000107 R_386_JUMP_SLOT   00000000   __gmon_start__       //offset 0xc(ebx)

000016c8  00000307 R_386_JUMP_SLOT   00000000   printf               //offset 0x10(ebx)

000016cc  00000407 R_386_JUMP_SLOT   00000000   __cxa_finalize       //offset 0x14(ebx)

//Offset000016c4、000016c8、000016cc位于.got.plt section There are no unwind sections in this file. Symbol table '.dynsym' contains 14 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 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses 3: 00000000 54 FUNC GLOBAL DEFAULT UND printf@GLIBC_2.0 (2) 4: 00000000 267 FUNC WEAK DEFAULT UND __cxa_finalize@GLIBC_2.1.3 (3) 5: 0000048c 212 FUNC GLOBAL DEFAULT 11 say_hello 6: 000016ec 0 NOTYPE GLOBAL DEFAULT ABS _end 7: 000016d4 0 NOTYPE GLOBAL DEFAULT ABS _edata 8: 000016dc 8 OBJECT GLOBAL DEFAULT 22 s 9: 000016e8 4 OBJECT GLOBAL DEFAULT 22 count 10: 000016d4 0 NOTYPE GLOBAL DEFAULT ABS __bss_start 11: 00000358 0 FUNC GLOBAL DEFAULT 9 _init 12: 00000598 0 FUNC GLOBAL DEFAULT 12 _fini 13: 000016e4 1 OBJECT GLOBAL DEFAULT 22 ch Section Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al [ 0] NULL 00000000 000000 000000 00 0 0 0 [ 1] .hash HASH 000000b4 0000b4 00004c 04 A 3 0 4 [ 2] .gnu.hash GNU_HASH 00000100 000100 000048 04 A 3 0 4 [ 3] .dynsym DYNSYM 00000148 000148 0000e0 10 A 4 1 4 [ 4] .dynstr STRTAB 00000228 000228 000091 00 A 0 0 1 [ 5] .gnu.version VERSYM 000002ba 0002ba 00001c 02 A 3 0 2 [ 6] .gnu.version_r VERNEED 000002d8 0002d8 000030 00 A 4 1 4 [ 7] .rel.dyn REL 00000308 000308 000038 08 A 3 0 4 [ 8] .rel.plt REL 00000340 000340 000018 08 A 3 10 4 [ 9] .init PROGBITS 00000358 000358 000030 00 AX 0 0 4 [10] .plt PROGBITS 00000388 000388 000040 04 AX 0 0 4 [11] .text PROGBITS 000003d0 0003d0 0001c8 00 AX 0 0 16 [12] .fini PROGBITS 00000598 000598 00001c 00 AX 0 0 4 [13] .rodata PROGBITS 000005b4 0005b4 00000a 00 A 0 0 1 [14] .eh_frame PROGBITS 000005c0 0005c0 000004 00 A 0 0 4 [15] .ctors PROGBITS 000015c4 0005c4 000008 00 WA 0 0 4 [16] .dtors PROGBITS 000015cc 0005cc 000008 00 WA 0 0 4 [17] .jcr PROGBITS 000015d4 0005d4 000004 00 WA 0 0 4 [18] .dynamic DYNAMIC 000015d8 0005d8 0000c8 08 WA 4 0 4  [19] .got PROGBITS 000016a0 0006a0 000018 04 WA 0 0 4 [20] .got.plt PROGBITS 000016b8 0006b8 000018 04 WA 0 0 4 [21] .data PROGBITS 000016d0 0006d0 000004 00 WA 0 0 4 [22] .bss NOBITS 000016d4 0006d4 000018 00 WA 0 0 4 [23] .comment PROGBITS 00000000 0006d4 00005a 00 0 0 1 [24] .debug_aranges PROGBITS 00000000 000730 000070 00 0 0 8 [25] .debug_pubnames PROGBITS 00000000 0007a0 000037 00 0 0 1 [26] .debug_info PROGBITS 00000000 0007d7 0001a8 00 0 0 1 [27] .debug_abbrev PROGBITS 00000000 00097f 0000aa 00 0 0 1 [28] .debug_line PROGBITS 00000000 000a29 00013c 00 0 0 1 [29] .debug_frame PROGBITS 00000000 000b68 000030 00 0 0 4 [30] .debug_str PROGBITS 00000000 000b98 000083 01 MS 0 0 1 [31] .debug_loc PROGBITS 00000000 000c1b 00002c 00 0 0 1 [32] .debug_ranges PROGBITS 00000000 000c48 000040 00 0 0 8 [33] .shstrtab STRTAB 00000000 000c88 00013b 00 0 0 1 [34] .symtab SYMTAB 00000000 001364 000430 10 35 54 4 [35] .strtab STRTAB 00000000 001794 00019e 00 0 0 1 

main函数中对于libhello.so中的函数say_hello的调用,会建立plt表(可减少relocation的次数,不需要对每个say_hello调用处都relocate,只需将GOT表中对应entryrelocate);
而对于count的使用,直接分配了固定地址!.rel.dyn节里标记为R_386_COPY类型,并将count变量的地址直接copy到libhello.so的GOT表对应的entry里。
参见: 【zz】从程序员角度看ELF:: 启动过程:: 静态的初始化

// test.c



#include <stdio.h>

#include <stdlib.h>



extern int count;



int main()

{

    say_hello();

    printf("count is %x\n", count);



    return 0;

}


jfo@lab:~/test$ gcc -ggdb -o test test.c -L. -lhello -Wl,-rpath,.



jfo@lab:~/test$ objdump -S test

 ...

int main()

{

 80484e4:       8d 4c 24 04             lea    0x4(%esp),�x

 80484e8:       83 e4 f0                and    $0xfffffff0,%esp

 80484eb:       ff 71 fc                pushl  -0x4(�x)

 80484ee:       55                      push   �p

 80484ef:       89 e5                   mov    %esp,�p

 80484f1:       51                      push   �x

 80484f2:       83 ec 14                sub    $0x14,%esp

    say_hello();

 80484f5:       e8 02 ff ff ff          call   80483fc <say_hello@plt>



    printf("count is %x\n", count);

 80484fa:       a1 08 97 04 08          mov    0x8049708,�x       //变量cout的地址固定!!!

 80484ff:       89 44 24 04             mov    �x,0x4(%esp)

 8048503:       c7 04 24 e0 85 04 08    movl   $0x80485e0,(%esp)

 804850a:       e8 0d ff ff ff          call   804841c <printf@plt>



    return 0;

 804850f:       b8 00 00 00 00          mov    $0x0,�x

}

 8048514:       83 c4 14                add    $0x14,%esp

 8048517:       59                      pop    �x

 8048518:       5d                      pop    �p

 8048519:       8d 61 fc                lea    -0x4(�x),%esp

 804851c:       c3                      ret

 804851d:       90                      nop

 804851e:       90                      nop

 804851f:       90                      nop



 ...







jfo@lab:~/test$ readelf -a test

...

Relocation section '.rel.dyn' at offset 0x37c contains 2 entries:

 Offset     Info    Type            Sym.Value  Sym. Name

080496e0  00000106 R_386_GLOB_DAT    00000000   __gmon_start__

08049708  00000905 R_386_COPY        08049708   count



Relocation section '.rel.plt' at offset 0x38c contains 4 entries:

 Offset     Info    Type            Sym.Value  Sym. Name

080496f0  00000107 R_386_JUMP_SLOT   00000000   __gmon_start__

080496f4  00000307 R_386_JUMP_SLOT   00000000   say_hello

080496f8  00000407 R_386_JUMP_SLOT   00000000   __libc_start_main

080496fc  00000507 R_386_JUMP_SLOT   00000000   printf



...

你可能感兴趣的:(关于-fPIC选项 和 GOT表)