使用不带GOT的位置无关代码

时间:2016-12-13 13:24:58

标签: c arm

在没有全局偏移表的情况下编译多个PIC文件时出现问题。

使用以下参数编译第一个文件onefile.c时,程序集不包含对GOT的引用:

  

arm-none-eabi-gcc.exe first.c -nosdlib -fPIE -march = armv7-a -o first.o

first.c

void function();
int main();

int main()
{
    void* function_pointer;
    function_pointer = &function;
}

void function()
{

}

大会:

.text:00008000 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:00008000                 EXPORT main
.text:00008000 main
.text:00008000
.text:00008000 var_8           = -8
.text:00008000 var_s0          =  0
.text:00008000
.text:00008000                 STR             R11, [SP,#-4+var_s0]!
.text:00008004                 ADD             R11, SP, #0
.text:00008008                 SUB             SP, SP, #0xC
.text:0000800C                 LDR             R3, =(function - 0x8018)
.text:00008010                 ADD             R3, PC, R3 ; function
.text:00008014                 STR             R3, [R11,#var_8]
.text:00008018                 MOV             R3, #0
.text:0000801C                 MOV             R0, R3
.text:00008020                 SUB             SP, R11, #0
.text:00008024                 LDR             R11, [SP+var_s0],#4
.text:00008028                 BX              LR
.text:00008028 ; End of function main

注意在地址0x8010中,寄存器R3如何在不使用GOT的情况下具有函数“function”的地址。

但是当将文件拆分为多个.c和.h文件时,结果正在改变

  

arm-none-eabi-gcc.exe twofiles1.c twofiles2.c -nostdlib -fPIE   -march = armv7-a -o twofiles.o

twofiles1.c:

#include "twofiles1.h"

int main()
{
    void* function_pointer;
    function_pointer = &function;
}

twofiles1.h:

#include "twofiles2.h"

int main();

twofiles2.c:

void function()
{

}

twofiles2.h:

void function();

组件:

.text:00008000 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:00008000                 EXPORT main
.text:00008000 main
.text:00008000
.text:00008000 var_8           = -8
.text:00008000 var_s0          =  0
.text:00008000
.text:00008000                 STR             R11, [SP,#-4+var_s0]!
.text:00008004                 ADD             R11, SP, #0
.text:00008008                 SUB             SP, SP, #0xC
.text:0000800C                 LDR             R2, =(_GLOBAL_OFFSET_TABLE_ - 0x8018)
.text:00008010                 ADD             R2, PC, R2 ; _GLOBAL_OFFSET_TABLE_
.text:00008014                 LDR             R3, =(function_ptr - 0x18054)
.text:00008018                 LDR             R3, [R2,R3] ; function
.text:0000801C                 STR             R3, [R11,#var_8]
.text:00008020                 MOV             R3, #0
.text:00008024                 MOV             R0, R3
.text:00008028                 SUB             SP, R11, #0
.text:0000802C                 LDR             R11, [SP+var_s0],#4
.text:00008030                 BX              LR
.text:00008030 ; End of function main

注意函数“function”的地址是如何计算 GOT的。这就是我想要克制的 是否有任何解决方案可以实现与第一个结果相同的装配?

1 个答案:

答案 0 :(得分:1)

编译器一次查看一个模块,因此不同的编译单元要求使用GOT。

关于PIC代码GCC man

  

<强> -fpic

     

如果目标计算机支持,则生成适用于共享库的位置无关代码(PIC)。 此类代码通过全局偏移表(GOT)访问所有常量地址。程序启动时动态加载程序解析GOT条目(动态加载程序不是GCC的一部分;它是操作系统的一部分)。如果链接的可执行文件的GOT大小超过计算机特定的最大大小,您从链接器收到一条错误消息,指示-fpic不起作用;在这种情况下,请使用-fPIC重新编译。 (这些最大值在SPARC上为8k,在AArch64上为28k,在m68k和RS / 6000上为32k。x86没有此限制。)   与位置无关的代码需要特殊支持,因此仅适用于某些机器。对于x86,GCC支持System for System的PIC,但不支持Sun 386i的PIC。为IBM RS / 6000生成的代码始终与位置无关。

强调我的