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

自定义ld脚本编译C代码触发ld内部错误ldlang.c 6101的原因与修复

问题分析与修复

问题背景

C代码(t79.c)

#include <stdio.h>

const char code[] __attribute__((section(".mySection"))) = "\xb8\x0d\x00\x00\x00\xc3";

int main(int argc, char **argv)
{
    int val = ((int(*)(void))code)();
    printf("val %d\n", val);
}
MEMORY
{
  my_region (RWX) : ORIGIN = 0x405340, LENGTH = 4K
}

SECTIONS
{
  .mySegment 0x405340 : {KEEP(*(.mySection))} > my_region
}

编译命令

gcc link.ld t79.c

错误输出

/usr/bin/ld: warning: link.ld contains output sections; did you forget -T?
/usr/bin/ld: internal error ../../ld/ldlang.c 6101
collect2: error: ld returned 1 exit status

环境信息

ld version: 2.34
gcc version: 9.4.0
uname -a:
Linux xxx 5.15.0-25-generic #25~20.04.2-Ubuntu SMP Mon Apr 11 08:31:42 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

补充:内部错误来自lang_size_relro_segment_1函数中的断言失败:

ASSERT (desired_end >= seg->base);

错误原因

  1. 编译命令参数错误:未使用-T参数指定链接脚本,gcc默认将link.ld当作普通目标文件处理,导致ld无法正确解析脚本中的输出段定义,触发"did you forget -T?"警告。
  2. 地址范围冲突:自定义段的起始地址0x405340与系统默认生成的RELRO(只读重定位)段地址范围重叠,ld在计算RELRO段大小的过程中,断言desired_end >= seg->base不成立,直接触发内部错误。

修复方案

方案1:修正编译命令,添加-T参数

使用-T参数明确指定链接脚本,正确命令如下:

gcc t79.c -T link.ld

方案2:调整自定义段地址,避免与默认段冲突

通过readelf -l a.out(先编译一个无自定义脚本的可执行文件)查看默认段的地址范围,选择一个空闲区间作为自定义段的起始地址,比如0x406000,修改后的链接脚本:

MEMORY
{
  my_region (RWX) : ORIGIN = 0x406000, LENGTH = 4K
}

SECTIONS
{
  .mySegment 0x406000 : {KEEP(*(.mySection))} > my_region
}

方案3:关闭RELRO特性(仅测试场景使用)

如果不需要RELRO的安全保护,可以添加-z norelro参数关闭该特性,绕过断言错误:

gcc t79.c -T link.ld -z norelro

注意:该方案会降低程序安全性,不建议在生产环境使用。


内容的提问来源于stack exchange,提问作者pmor

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 05:50:27