在没有全局偏移表的情况下编译多个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的。这就是我想要克制的 是否有任何解决方案可以实现与第一个结果相同的装配?
答案 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生成的代码始终与位置无关。
强调我的