ARM Cortex-M构建PIE需重新编译带-fPIE的newlib-nano吗?
问题描述
我正在为ARM Cortex-M微控制器开发单体式独立位置无关可执行文件(PIE),该文件既不调用外部函数,也不被外部实体调用。我实现了自定义加载/重定位器,它接收原始二进制文件(非ELF格式)及元数据(段偏移、大小、入口点),将文件加载到RAM、完成重定位后跳转到入口点。
二进制文件通过-fPIE编译并以-pie链接。根据GCC手册,使用-pie时需指定与编译一致的选项(如-fPIE)才能获得可预测结果。我自行开发的所有目标文件均以-fPIE构建,但不确定所使用的arm-none-eabi工具链中的newlib-nano是否基于-fPIE编译。
目前代码运行正常,但我担心这只是巧合。当前我仅使用newlib的少量函数:strlen、memcpy、memcmp、memset、strchr、strcspn、strncmp、strncpy、strrchr、strspn,不涉及动态内存分配且无相关计划。此外,编译器还自动引入了libgcc的辅助函数:__aeabi_uldivmod、__popcountsi2、__udivmoddi4、__aeabi_ldiv0,这些函数未在我的代码中直接引用。
现咨询:在此类嵌入式场景下,为确保PIE安全可靠,是否需要重新编译带-fPIE的newlib-nano(及可能的libgcc),还是仅编译应用代码时使用-fPIE即可?
回答
核心结论
针对你当前的使用场景,不需要重新编译带-fPIE的newlib-nano和libgcc,仅编译应用代码时使用-fPIE即可保证PIE的安全可靠性。具体原因如下:
1. 你使用的newlib-nano函数特性
你用到的字符串/内存操作函数(strlen、memcpy等)均为无全局依赖的纯函数:
- 它们仅依赖传入的参数,不访问固定内存地址的全局变量或静态数据;
- 即使未用
-fPIE编译,这类函数的实现也会采用基于寄存器的相对寻址,而非绝对地址引用,天然适配PIE环境; - 你明确排除了动态内存分配相关函数(如
malloc、free),这类函数才会依赖全局堆管理结构,可能存在绝对地址风险,而你完全没涉及这部分。
2. libgcc辅助函数的兼容性
编译器自动引入的__aeabi_uldivmod、__popcountsi2等libgcc辅助函数:
- ARM官方提供的arm-none-eabi工具链中,libgcc的实现本身就考虑了嵌入式场景的位置无关需求,这些辅助函数大多是位置无关的;
- 这类函数仅处理传入的参数,无全局状态依赖,编译时即使未加
-fPIE,链接器通过-pie选项处理后,也能生成正确的重定位信息,被你的自定义加载器正确处理。
3. 当前运行正常并非巧合
你代码能正常运行,本质是因为用到的所有第三方函数都不包含绝对地址引用,你的自定义加载器只需处理应用代码本身的重定位即可。只要后续不引入依赖全局状态的newlib函数,就不会出现PIE兼容性问题。
特殊情况提醒
如果后续扩展功能时用到了动态内存分配、线程安全相关的newlib函数,或者某个函数出现地址相关的崩溃,再考虑重新编译带-fPIE的newlib-nano版本。
内容的提问来源于stack exchange,提问作者mastupristi

