如何在不修改源码且保留函数引用的前提下重命名目标文件中的函数?
同编译单元内函数引用与实体分离解决方案
你遇到的问题很典型:当两个函数在同一编译单元时,普通的符号重定义或--wrap技巧都不生效,因为编译器会生成内部直接调用,而非外部符号引用。结合你不能修改源码、用了-ffunction-sections编译的前提,我们可以通过拆分目标文件段+链接脚本的方式实现需求:让foo对bar的调用指向指定绝对地址,同时原bar实体被分配到其他地址。
具体操作步骤
1. 编译生成目标文件
先正常编译你的源码,保留每个函数的独立段:
gcc -c -ffunction-sections file.c -o file.o
2. 拆分目标文件的函数段
因为-ffunction-sections让每个函数都在单独的.text.xxx段里,我们可以把foo和bar拆成两个独立的目标文件:
- 提取
bar函数所在的段,生成仅包含bar的目标文件:objcopy --only-section .text.bar file.o bar_only.o - 移除原file.o中的
bar段,生成仅包含foo的目标文件(此时foo里对bar的引用会变成未定义的外部符号):objcopy --remove-section .text.bar file.o foo_only.o
3. 重命名原bar函数的符号
把bar_only.o里的bar符号重命名为file_bar,避免和我们要定义的外部bar冲突:
objcopy --redefine-sym bar=file_bar bar_only.o
4. 编写链接脚本(linker.ld)
创建链接脚本,指定bar的绝对地址,同时安排file_bar的存放位置:
SECTIONS { /* 保留默认的.text段逻辑,确保代码正常加载 */ .text : { *(.text.foo) /* 先放foo函数 */ file_bar = .; /* 这里可以指定file_bar的地址,或者用当前地址自动分配 */ *(.text.file_bar) /* 放重命名后的原bar函数 */ } /* 强制bar符号指向你需要的绝对地址 */ PROVIDE(bar = 0x12345678); }
把0x12345678替换成你实际需要的绝对地址。
5. 链接生成最终可执行文件
用gcc调用链接器,加载我们的链接脚本:
gcc -Wl,-Tlinker.ld foo_only.o bar_only.o -o output
验证结果
用反汇编工具查看最终文件:
objdump -d output
你会看到:
foo函数里的调用指令会直接跳转到你指定的0x12345678地址- 原
bar函数的代码会以file_bar为符号名,出现在链接脚本指定的位置
这样就完美实现了你的需求:不修改源码,保留foo对bar的调用指向指定地址,同时原bar实体被分配到其他位置。
内容的提问来源于stack exchange,提问作者techgreed




