2016-05-12 123 views
4

如果一個重要的程序被編譯使用下面的命令:爲什麼程序與-fpic和-pie編譯有重定位表?

arm-none-eabi-gcc -shared -fpic -pie --specs=nosys.specs simple.c -o simple.exe 

和重定位項都印有該命令:

arm-none-eabi-readelf simple.exe -r 

有一串重定位的條目部分(見下文)。

因爲-fpic/-pie標誌會導致編譯器生成一個位置無關的可執行文件,所以我的天真(明顯不正確)假設是不需要重定位表,因爲加載器可以將可執行映像放在任何地方而沒有問題。那麼,爲什麼在那裏有一個重定位表,這是否表明代碼實際上並不是獨立的?

Relocation section '.rel.dyn' at offset 0x82d4 contains 37 entries: 
Offset  Info Type   Sym.Value Sym. Name 
000084a8 00000017 R_ARM_RELATIVE 
000084d0 00000017 R_ARM_RELATIVE 
00008508 00000017 R_ARM_RELATIVE 
00008510 00000017 R_ARM_RELATIVE 
0000855c 00000017 R_ARM_RELATIVE 
00008560 00000017 R_ARM_RELATIVE 
00008564 00000017 R_ARM_RELATIVE 
00008678 00000017 R_ARM_RELATIVE 
0000867c 00000017 R_ARM_RELATIVE 
0000870c 00000017 R_ARM_RELATIVE 
00008710 00000017 R_ARM_RELATIVE 
00008714 00000017 R_ARM_RELATIVE 
00008718 00000017 R_ARM_RELATIVE 
00008978 00000017 R_ARM_RELATIVE 
000089dc 00000017 R_ARM_RELATIVE 
000089e0 00000017 R_ARM_RELATIVE 
00008abc 00000017 R_ARM_RELATIVE 
00008ae4 00000017 R_ARM_RELATIVE 
00018af4 00000017 R_ARM_RELATIVE 
00018af8 00000017 R_ARM_RELATIVE 
00018afc 00000017 R_ARM_RELATIVE 
00018c04 00000017 R_ARM_RELATIVE 
00018c08 00000017 R_ARM_RELATIVE 
00018c0c 00000017 R_ARM_RELATIVE 
00018c34 00000017 R_ARM_RELATIVE 
00019028 00000017 R_ARM_RELATIVE 
000084cc 00000c02 R_ARM_ABS32  00000000 __libc_fini 
0000850c 00000602 R_ARM_ABS32  00000000 __deregister_frame_inf 
00008558 00001302 R_ARM_ABS32  00000000 __register_frame_info 
00008568 00001202 R_ARM_ABS32  00000000 _Jv_RegisterClasses 
00008664 00000d02 R_ARM_ABS32  00000000 __stack 
00008668 00000a02 R_ARM_ABS32  00000000 hardware_init_hook 
0000866c 00000802 R_ARM_ABS32  00000000 software_init_hook 
00008670 00000502 R_ARM_ABS32  0001902c __bss_start__ 
00008674 00000702 R_ARM_ABS32  00019048 __bss_end__ 
0000897c 00001402 R_ARM_ABS32  00000000 free 
00008ac0 00000402 R_ARM_ABS32  00000000 malloc 

Relocation section '.rel.plt' at offset 0x83fc contains 4 entries: 
Offset  Info Type   Sym.Value Sym. Name 
00018be8 00000416 R_ARM_JUMP_SLOT 00000000 malloc 
00018bec 00000616 R_ARM_JUMP_SLOT 00000000 __deregister_frame_inf 
00018bf0 00001316 R_ARM_JUMP_SLOT 00000000 __register_frame_info 
00018bf4 00001416 R_ARM_JUMP_SLOT 00000000 free 
+0

http://stackoverflow.com/questions/3544035/what-is-the-difference-between-fpic-and-fpic-gcc-parameters/3544211 – user3159253

+0

可重定位意味着符號需要一個間接層,因爲一個可執行文件對另一個可執行文件的位置可能不同靜態鏈接庫的位置在靜態鏈接時固定。 – jxh

回答

0

可執行由幾個部分。 雖然實際執行細節上有所不同,這大致可以分爲四組:

  1. 只讀可執行代碼,也被稱爲「文本」
  2. 只讀常量數據(全局常量)
  3. (初始化)讀寫數據(與初始化的全局變量)
  4. 未初始化的讀寫數據(其它全局變量,初始化爲0)

非位置無關的代碼合作對函數,全局變量和全局常量的地址有很多引用。

只讀數據和初始化的讀寫數據有時包含引用的函數,全局變量和全局constsants地址:

int x; 
int *y = &x; // y needs a relocation. 

裝載機可以根據搬遷移居代碼,有隻有兩個問題:

  1. 重定位需要時間在程序啓動/庫加載
  2. 如果我們重新定位,我們現在有一個內部修改的文本段副本,這對於加載我們的庫的每個進程都不同,所以我們將浪費RAM。

現在對於真正的答案: PIC的目的是通過擺脫文字搬遷,不擺脫所有搬遷,解決了上述問題。

只讀數據和初始化數據中的重定位相對較少,所以(1.)和(2.)都不是問題。我們甚至不關心(2)讀寫數據,因爲我們需要爲每個進程單獨拷貝這些數據。實際上,編譯器無法使數據與位置無關,因爲如果您要求全局編譯器,則編譯器別無選擇,只能將指針放在那裏。

現在,代碼如何與位置無關? 這取決於平臺,但它通常涉及一些相對低效的操作,或者處理器對用於以獨立於位置的方式訪問數據的更高效指令中使用的最大偏移量施加任意限制。而且,動態鏈接意味着某些函數的地址甚至不被稱爲相對偏移量。 因此,編譯器傾向於使用包含實際地址的表,代碼將從表中查找實際地址。這些表格,不同平臺上的GOT,TOC,PLT以及其他一些名稱可能會是Constant Data,並且會有很多重定位。

如果無法避免重新定位,我們的想法是將它們全部放到一個地方,以最大限度地減少問題(1.)和(2.)。