如何让lld/mold链接器将变量放入指定段?g++链接正常
问题
我通过链接脚本实现将函数指针放入指定段,相关代码如下:
A.ld 链接脚本
SECTIONS { .rel.rodata.func_reg : { PROVIDE(func_reg_start = .); *(.func_reg.aaa.*) PROVIDE(func_reg_end = .); ... } } INSERT AFTER .text;
A.hpp 头文件
typedef bool (*func_type)(); #define ADD_FUNC(idx, func) \ static func_type i_##idx##func __attribute__((section(".func_reg." #idx "." #func))) = (func);
A.cpp 执行逻辑
extern uint64_t func_reg_start[]; extern uint64_t func_reg_end[]; uint64_t func_size = func_reg_end - func_reg_start; for (uint64_t i = 0; i < func_size; j += sizeof(func_type)) { auto func = *(func_type*)(func_reg_start + i); func(); // 期望执行B.cpp/C.cpp中的test()/test2() }
B.cpp 注册函数
static bool test() { std::cout << "test" << std::endl; return true; } ADD_FUNC(aaa, test) // 期望test()指针放入".func_reg.aaa.test"段
C.cpp 注册函数
static bool test2() { std::cout << "test2" << std::endl; return true; } ADD_FUNC(aaa, test2) // 期望test2()指针放入".func_reg.aaa.test2"段
通过CMake选项附加链接脚本:
target_link_options(${BIN_TARGET} PRIVATE -Wl,-T${CMAKE_CURRENT_SOURCE_DIR}/A.ld)
该实现使用GCC链接器时运行正常,但切换到LLD和Mold链接器后,编译构建无报错,但A.cpp中的func_size始终为0,指定段无内容,没有函数被执行。需要修改代码让其在LLD和Mold下正常工作。
解决方案
1. 修正链接脚本的段定义与保留规则
LLD和Mold对未直接引用的段优化更严格,需调整段属性并强制保留目标内容:
SECTIONS { .rodata.func_reg : { PROVIDE_HIDDEN(func_reg_start = .); KEEP(*(.func_reg.aaa.*)) PROVIDE_HIDDEN(func_reg_end = .); ... } } INSERT AFTER .rodata;
- 将
.rel.rodata.func_reg改为.rodata.func_reg:函数指针是只读常量,无需重定位段,放在标准只读数据段类下更合理。 KEEP():强制链接器保留匹配的段内容,避免被优化丢弃。PROVIDE_HIDDEN():避免符号全局导出,同时保证链接脚本作用域内可见。INSERT AFTER .rodata:贴合标准内存布局,减少兼容性问题。
2. 修正符号类型与遍历逻辑
A.cpp中符号类型应使用字节指针(char[]),避免指针运算步长错误,同时修正循环变量笔误:
extern char func_reg_start[]; extern char func_reg_end[]; uint64_t func_size = func_reg_end - func_reg_start; for (uint64_t i = 0; i < func_size; i += sizeof(func_type)) { auto func = *(func_type*)(func_reg_start + i); func(); }
3. 阻止编译器优化注册变量
在ADD_FUNC宏中添加__attribute__((used)),告知编译器必须保留该变量:
typedef bool (*func_type)(); #define ADD_FUNC(idx, func) \ static func_type i_##idx##func __attribute__((section(".func_reg." #idx "." #func), used)) = (func);
LLD/Mold依赖used属性识别需保留的符号,否则编译阶段可能直接丢弃变量。
4. 验证段内容(可选)
通过以下命令确认函数指针是否被正确放入目标段:
objdump -s -j .rodata.func_reg your_binary
内容的提问来源于stack exchange,提问作者JSK
相关产品推荐
相关产品推荐

