You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 22:46:24