关于-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



...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值