编译兼具PIC与PIE特性且含外部符号的代码问题求助
实现无GOT依赖的位置独立ARM二进制文件
需求回顾
要生成一个位置独立的ARM二进制文件,满足两个核心要求:
- 直接向固定绝对地址
0x00001000写入函数指针 - 通过文本段内的相对偏移获取目标函数地址,完全不依赖GOT(全局偏移表)
原方案中使用外部符号指定绝对地址、常规编译选项导致函数地址依赖GOT或为绝对地址,无法满足位置独立性要求。
解决方案
1. 修改C代码:硬编码绝对地址+相对偏移计算函数地址
直接在代码中硬编码目标绝对地址,同时利用同一文本段内函数的固定相对偏移,计算出位置无关的函数地址:
// main.c #include <stdint.h> // 直接硬编码目标全局内存地址,避免外部符号依赖 #define TARGET_ADDR ((void**)0x00001000) int some_function(void) { return 1; } int main(void) { // 利用main和some_function的固定相对偏移计算函数地址 // 同一.text段内的函数相对偏移在编译后固定,不受加载地址影响 int (*func_ptr)() = (int (*)())((char*)main + ((char*)&some_function - (char*)main)); // 直接写入指定绝对地址 *TARGET_ADDR = func_ptr; return 0; }
2. 调整编译链接选项
使用以下命令编译,确保生成位置独立且无GOT依赖的二进制:
arm-linux-gnueabi-gcc main.c -Os -nostdlib -nolibc -nodefaultlibs -nostartfiles \ -march=armv5tej -mcpu=arm926ej-s -mthumb -o main \ -Wl,-e,main -Wl,--section-start=.text=0xffff0000 \ -fpie -fno-plt -fno-pic-data-is-text-relative
选项说明:
-fpie:生成位置独立的可执行代码,确保指令使用PC相对寻址-fno-plt:禁止生成过程链接表,避免间接函数调用依赖-fno-pic-data-is-text-relative:确保数据引用不强制依赖文本段相对寻址(这里我们直接硬编码绝对地址,不受影响)- 保留原有的
-nostdlib等选项,避免引入标准库依赖
原理说明
- 绝对地址写入:通过宏直接硬编码
0x00001000,编译器会直接生成存储到该地址的指令,无需通过GOT间接访问 - 位置无关的函数地址:
main和some_function处于同一.text段,编译后两者的相对偏移固定。无论二进制加载到哪个内存地址,通过main的当前地址加上固定偏移,就能准确得到some_function的实际运行地址,完全不需要GOT或动态链接的介入
验证
编译完成后,使用arm-linux-gnueabi-objdump -d main反汇编查看main函数:
- 会看到计算函数地址的指令使用PC相对偏移或基于
main地址的加法操作 - 写入
0x00001000的指令为直接绝对地址访问,无GOT相关的间接引用
内容的提问来源于stack exchange,提问作者TJR
相关产品推荐
相关产品推荐

