0%

GCC 编译参数 -fpic

记录-fpic参数作用及对执行效率的影响
动态链接执行很复杂,比静态链接执行时间长
但是,极大的节省了sizePIC和动态链接技术是计算机发展史上非常重要的一个里程碑

gcc 参数

相关参数可以使用man gcc查看具体解释

  • -fpic,该选项用于生成位置无关代码 (Position-Independent Code),尤其被用于共享库的创建。使用该选项编译出的代码在访问所有常量地址时,会通过全局偏移表GOT进行计算得到。动态加载器将会在目标程序启动的时候解析GOT的入口(动态加载器不是GCC的一部分,其属于操作系统的一部分)。如果对于需要进行链接的可执行程序来说, 使用的GOT大小超过了machine-specific值指定的最大大小,你将会得到一条来自链接器的错误信息,以表明-fpic无法正常工作;在这种情况下,会使用-fPIC选项再重新编译一次。(这个最大大小限制在SPARC上为8k,在m68kRS/6000上为32k,而在x86上没有限制)
  • -fPIC,可以避免全局偏移表大小限制的问题外,其它方面和上面的一样
  • -shared,从GCC来看,shared应该是包含-fPIC选项的,但似乎不是所以系统都支持,所以最好显式加上-fPIC选项

产生的代码中,没有绝对地址,全部使用相对地址,故而代码可以被加载器加载到内存的任意位置,都可以正确的执行

如果不加-fPIC, 则加载.so文件的代码段时,代码段引用的数据对象需要重定位,重定位会修改代码段的内容,这就造成每个使用这个.so文件代码段的进程在内核里都会生成这个.so文件代码段的copy. 每个copy都不一样,取决于这个.so文件代码段和数据段内存映射的位置

不加-fPIC编译出来的so, 是要再加载时根据加载到的位置再次重定位的。(因为它里面的代码并不是位置无关代码)

代码

non-PICPIC代码的区别主要在于access global data, jump label 的不同

  • GOTdata section, 是一个table, 除专用的几个entry,每个`entry 的内容可以再执行的时候修改
  • PLTtext section, 是一段一段的code,执行中不需要修改

access global data

  • non-pic: ld r3, var1
  • pic: ld r3, var1-offset@GOT.
    GOT表的indexvar1-offset的地方处指示的地址处装载一个值,即var1-offset@GOT处的 4 个byte其实就是var1的地址。这个地址只有在运行的时候才知道,是由dynamic-loader(ld-linux.so)填进去的

jump label

  • non-pic: jump printf. 调用printf
  • pic: jump printf-offset@GOT.
    跳到GOT表的indexprintf-offset的地方处指示的地址去执行。这个地址处的代码摆放在.plt section

每个外部函数对应一段这样的代码,其功能是呼叫dynamic-loader(ld-linux.so)来查找函数的地址(本例中是printf),然后将其地址写到GOT表的indexprintf-offset的地方,同时执行这个函数。这样,第 2 次呼叫printf的时候,就会直接跳到printf的地址,而不必再查找了。

Example

$ objdump -xa airkiss

airkiss:     文件格式 elf64-x86-64
airkiss
体系结构:i386:x86-64, 标志 0x00000150:
HAS_SYMS, DYNAMIC, D_PAGED
起始地址 0x0000000000001b80

程序头:
    PHDR off    0x0000000000000040 vaddr 0x0000000000000040 paddr 0x0000000000000040 align 2**3
         filesz 0x00000000000001f8 memsz 0x00000000000001f8 flags r--
  INTERP off    0x0000000000000238 vaddr 0x0000000000000238 paddr 0x0000000000000238 align 2**0
         filesz 0x000000000000001c memsz 0x000000000000001c flags r--
    LOAD off    0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**21
         filesz 0x000000000000bc70 memsz 0x000000000000bc70 flags r-x
    LOAD off    0x000000000000cb70 vaddr 0x000000000020cb70 paddr 0x000000000020cb70 align 2**21
         filesz 0x00000000000008c8 memsz 0x0000000000000cf8 flags rw-
 DYNAMIC off    0x000000000000cba0 vaddr 0x000000000020cba0 paddr 0x000000000020cba0 align 2**3
         filesz 0x0000000000000200 memsz 0x0000000000000200 flags rw-
    NOTE off    0x0000000000000254 vaddr 0x0000000000000254 paddr 0x0000000000000254 align 2**2
         filesz 0x0000000000000044 memsz 0x0000000000000044 flags r--
EH_FRAME off    0x000000000000accc vaddr 0x000000000000accc paddr 0x000000000000accc align 2**2
         filesz 0x000000000000031c memsz 0x000000000000031c flags r--
   STACK off    0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**4
         filesz 0x0000000000000000 memsz 0x0000000000000000 flags rw-
   RELRO off    0x000000000000cb70 vaddr 0x000000000020cb70 paddr 0x000000000020cb70 align 2**0
         filesz 0x0000000000000490 memsz 0x0000000000000490 flags r--

动态节:
  NEEDED               libiw.so.30
  NEEDED               libc.so.6
  INIT                 0x0000000000001738
  FINI                 0x0000000000009390
  INIT_ARRAY           0x000000000020cb70
  INIT_ARRAYSZ         0x0000000000000008
  FINI_ARRAY           0x000000000020cb78
  FINI_ARRAYSZ         0x0000000000000008
  GNU_HASH             0x0000000000000298
  STRTAB               0x0000000000000a28
  SYMTAB               0x00000000000002d8
  STRSZ                0x00000000000002f2
  SYMENT               0x0000000000000018
  DEBUG                0x0000000000000000
  PLTGOT               0x000000000020cda0
  PLTRELSZ             0x0000000000000618
  PLTREL               0x0000000000000007
  JMPREL               0x0000000000001120
  RELA                 0x0000000000000e08
  RELASZ               0x0000000000000318
  RELAENT              0x0000000000000018
  FLAGS                0x0000000000000008
  FLAGS_1              0x0000000008000001
  VERNEED              0x0000000000000db8
  VERNEEDNUM           0x0000000000000001
  VERSYM               0x0000000000000d1a
  RELACOUNT            0x0000000000000016

版本引用:
  required from libc.so.6:
    0x0d696917 0x00 05 GLIBC_2.7
    0x06969194 0x00 04 GLIBC_2.14
    0x0d696914 0x00 03 GLIBC_2.4
    0x09691a75 0x00 02 GLIBC_2.2.5

节:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .interp       0000001c  0000000000000238  0000000000000238  00000238  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  1 .note.ABI-tag 00000020  0000000000000254  0000000000000254  00000254  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .note.gnu.build-id 00000024  0000000000000274  0000000000000274  00000274  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  3 .gnu.hash     00000040  0000000000000298  0000000000000298  00000298  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .dynsym       00000750  00000000000002d8  00000000000002d8  000002d8  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  5 .dynstr       000002f2  0000000000000a28  0000000000000a28  00000a28  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  6 .gnu.version  0000009c  0000000000000d1a  0000000000000d1a  00000d1a  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  7 .gnu.version_r 00000050  0000000000000db8  0000000000000db8  00000db8  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  8 .rela.dyn     00000318  0000000000000e08  0000000000000e08  00000e08  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  9 .rela.plt     00000618  0000000000001120  0000000000001120  00001120  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 10 .init         00000017  0000000000001738  0000000000001738  00001738  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 11 .plt          00000420  0000000000001750  0000000000001750  00001750  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 12 .plt.got      00000008  0000000000001b70  0000000000001b70  00001b70  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 13 .text         00007810  0000000000001b80  0000000000001b80  00001b80  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 14 .fini         00000009  0000000000009390  0000000000009390  00009390  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 15 .rodata       0000192a  00000000000093a0  00000000000093a0  000093a0  2**5
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 16 .eh_frame_hdr 0000031c  000000000000accc  000000000000accc  0000accc  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 17 .eh_frame     00000c88  000000000000afe8  000000000000afe8  0000afe8  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 18 .init_array   00000008  000000000020cb70  000000000020cb70  0000cb70  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 19 .fini_array   00000008  000000000020cb78  000000000020cb78  0000cb78  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 20 .data.rel.ro  00000020  000000000020cb80  000000000020cb80  0000cb80  2**5
                  CONTENTS, ALLOC, LOAD, DATA
 21 .dynamic      00000200  000000000020cba0  000000000020cba0  0000cba0  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 22 .got          00000248  000000000020cda0  000000000020cda0  0000cda0  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 23 .data         00000438  000000000020d000  000000000020d000  0000d000  2**5
                  CONTENTS, ALLOC, LOAD, DATA
 24 .bss          00000428  000000000020d440  000000000020d440  0000d438  2**5
                  ALLOC
 25 .comment      0000002b  0000000000000000  0000000000000000  0000d438  2**0
                  CONTENTS, READONLY
 26 .debug_aranges 00000150  0000000000000000  0000000000000000  0000d463  2**0
                  CONTENTS, READONLY, DEBUGGING
 27 .debug_info   00006926  0000000000000000  0000000000000000  0000d5b3  2**0
                  CONTENTS, READONLY, DEBUGGING
 28 .debug_abbrev 00000ec3  0000000000000000  0000000000000000  00013ed9  2**0
                  CONTENTS, READONLY, DEBUGGING
 29 .debug_line   000018d1  0000000000000000  0000000000000000  00014d9c  2**0
                  CONTENTS, READONLY, DEBUGGING
 30 .debug_str    00001e7a  0000000000000000  0000000000000000  0001666d  2**0
                  CONTENTS, READONLY, DEBUGGING
 31 .debug_ranges 00000030  0000000000000000  0000000000000000  000184e7  2**0
                  CONTENTS, READONLY, DEBUGGING