C编译报错relocation truncated to fit: R_X86_64_PC32 against symbol `b' defined in .bss

本文探讨了在Linux环境下编译大型程序时遇到的内存限制问题,特别是当单个数组大小超过2G时的解决方案。介绍了如何使用-gcc编译选项-mcmodel来调整静态数组的大小要求,并讨论了-O优化参数的作用。

   问题如下图所示:(.text+0x53a): relocation truncated to fit: R_X86_64_32S against `.bss'

    以前在linux中编译程序,从来没有遇到过这种问题,今天第一次遇到。查了一些资料发现时内存的限制,自己还有些疑问,以前编译内存大小是4G的程序都没出现过这种错误。

      看到一些博文中说是内存超过2G会出现问题。需要添加编译选项:-mcmodel

调整编译时的对静态数组要求的大小:-mcmodel=medium(中级)  -mcmodel=large(高级)

 具体编译选项添加位置:

       gcc -mcmodel=medium -o  stream2g_10  stream.c

或者在makefile文件中对应位置添加即可。

 

        找了以前编译的命令 gcc -O stream.c -o stream  就顺利通过了,-O这个优化参数也好神奇。

        


       但是-O失效的时候,还是-mcmodel 比较实用,当单个数组大小为2G,这个代码占用内存6G时,-O已经解决不了问题。
---------------------
作者:lisary_2017
来源:优快云
原文:https://blog.youkuaiyun.com/ai297313/article/details/42711837
版权声明:本文为博主原创文章,转载请附上博文链接!

<think>我们面对的是一个编译链接错误:"relocation truncated to fit: R_X86_64_PC32 against .bss"。这个错误通常发生在64位系统中,当程序试图访问一个位于.bss段(存储未初始化全局变量)的大数组或大对象时,由于地址偏移量超出了32位有符号整数的范围(即超过2GB),导致链接器无法生成正确的重定位信息。 根据引用[1][2][4]的建议,我们可以通过添加编译选项`-mcmodel=medium`来解决。这是因为默认的编译模式(small)假设代码和静态数据的总大小不会超过2GB,而medium模式则允许数据段超过这个限制(但代码段仍受限制)。 解决步骤: 1. 确认问题:首先,这个错误通常是因为程序中定义了非常大的全局数组或静态数组,导致在链接时地址偏移过大。 2. 修改编译选项:在编译命令中加入`-mcmodel=medium`。 例如:`g++ -mcmodel=medium -o your_program your_source.cpp` 或者在Makefile中对应位置添加。 3. 如果使用了大数组,并且确实需要非常大的内存,还可以考虑使用`-mcmodel=large`,但这种模式效率较低,因为访问全局数据和代码都会使用64位绝对地址,导致代码体积增大。 4. 另外,引用[1][4]提到,有时使用优化选项`-O`也能避开这个问题,因为优化可能会改变内存布局或使用寄存器优化掉一些大数组访问。但这并非总是有效,尤其是在数组确实非常大的时候。 注意事项: - `-mcmodel=medium`选项可能会使代码运行效率略有下降,因为对于大模型的访问需要额外的指令。 - 在共享库中使用`-mcmodel=medium`可能不太合适,因为它要求数据段在2GB以内,而共享库通常被映射到不同的地址空间。 其他解决方案: 1. 如果可能,减少大数组的大小。 2. 将大数组改为动态分配(使用堆内存),因为堆内存不受此限制。例如,将全局数组改为用`new`分配。 例如:将 int huge_array[10000000]; 改为: int* huge_array = new int[10000000]; 并在适当的时候释放。 3. 如果是多个大数组,可以考虑只将其中一部分改为动态分配。 为什么会出现这个错误? 在64位系统中,默认的small内存模型假设程序的数据和代码总大小在2GB以内,因此可以使用32位相对偏移量来访问数据和代码(这可以生成更紧凑的代码)。但是,当程序的数据(特别是.bss段中的未初始化数据)超过2GB时,32位的偏移量就无法表示从当前指令到目标数据的距离,导致重定位时被截断。 因此,主要解决方案是使用更大的内存模型(medium),或者避免使用过大的静态数据。 下面是一个示例,展示如何修改编译命令: 假设原编译命令为: g++ main.cpp -o main 修改为: g++ -mcmodel=medium main.cpp -o main 如果是在Makefile中,则在CXXFLAGS中添加: CXXFLAGS += -mcmodel=medium 需要注意的是,这个选项对于链接器也有影响,因此需要确保链接命令也包含这个选项(通常编译命令会传递给链接器)。 如果问题仍然存在,可能需要检查是否还有其他超大的静态数据,或者考虑使用动态分配。 根据引用[3]提供的链接,我们可以进一步了解`-mcmodel`选项: - small: 默认模式,数据和代码总大小不超过2GB,访问使用32位相对偏移。 - medium: 数据段可以超过2GB(但单个数据对象仍必须小于2GB),代码段仍在2GB内。对于大数组,这种模式会使用64位绝对地址来访问,因此不会出现截断错误。 - large: 代码和数据都可以超过2GB,但是效率更低。 因此,通常首选medium模式。 如果动态分配不可行,并且使用`-mcmodel=medium`仍然不能解决问题,那么可能需要尝试`-mcmodel=large`,但要注意性能影响。 另外,引用[5]提到一个具体场景(dijkstra+dfs)出现了段错误,这可能也是由于静态分配了大数组导致栈溢出或其他问题,但与本错误不同。我们的错误是链接错误,而引用[5]是运行时错误。 总结:解决这个编译链接错误的主要方法是使用`-mcmodel=medium`编译选项,或者将大数组改为动态分配。 下面是动态分配的例子: 原代码: // 全局大数组 double bigArray[100000000]; // 假设大小超过2GB 修改为: double* bigArray = nullptr; // 全局指针 int main() { bigArray = new double[100000000]; // ... 使用 bigArray delete[] bigArray; return 0; } 这样,数组就被分配在堆上,而不是.bss段,因此不会导致重定位问题。 另外,如果数组非常大,动态分配时也要注意检查分配是否成功,以及确保释放。 最后,如果使用动态分配,记得在不需要时释放内存,避免内存泄漏。 我们推荐优先考虑动态分配,因为它不会影响整个程序的编译模式,而且更加灵活。但如果程序中有多处大数组,修改起来比较麻烦,那么使用`-mcmodel=medium`可能更方便。 请根据实际情况选择解决方案。 </think>### 解决 `relocation truncated to fit: R_X86_64_PC32 against .bss` 错误的方法 该错误是64位系统下编译大型C++程序时的常见链接问题,根本原因是**静态数据(如全局数组)过大导致地址偏移超出32位限制**。以下是逐步解决方案: #### 1. **首选方案:添加编译选项 `-mcmodel=medium`** ```bash g++ -mcmodel=medium -o your_program your_source.cpp ``` - **原理**:默认的 `-mcmodel=small` 模式要求静态数据 ≤ 2GB,`medium` 模式允许数据段更大(但代码段仍须 ≤ 2GB)[^1][^3] - **副作用**: - 可能略微降低性能(访问全局变量需更多指令) - 不适用于共享库[^3] - Makefile 中添加示例: ```makefile CXXFLAGS += -mcmodel=medium ``` #### 2. **替代方案:使用动态内存分配** 将大型全局数组改为堆分配: ```cpp // 原代码(错误) double huge_array[100000000]; // 位于.bss段 // 修改后(正确) double* huge_array = new double[100000000]; // 堆内存 ``` - **优点**:彻底避免重定位问题,不依赖编译选项 - **注意**:需手动管理内存(`delete[]`) #### 3. **其他解决选项** | 编译选项 | 适用场景 | 限制 | |------------------|----------------------------------|--------------------------| | `-mcmodel=large` | 代码+数据总和 > 2GB | 性能损失更大[^3] | | `-O` 优化 | 小规模数据溢出(优化后可能满足) | 对 >2GB 数组无效[^1][^4] | | `-fPIC` | 生成位置无关代码 | 主要用于共享库 | #### 错误根本原因 - 在x86_64架构中,`.bss` 段存放**未初始化的全局变量** - `R_X86_64_PC32` 重定位要求32位偏移地址(范围 ±2GB) - 当程序加载时,若变量地址与指令的距离超过2GB,链接器无法生成正确偏移[^1][^3] > **典型触发场景**:定义超过2GB的全局数组(如 `char huge[2147483648];`)[^1][^4] #### 验证方案 通过 `size` 命令检查段大小: ```bash size your_program ``` 若 `.bss` 段接近 2GB (2147483648 bytes),即可确认问题。 --- ### 相关问题 1. 使用 `-mcmodel=medium` 后程序性能会下降多少? 2. 如何动态分配超过2GB的内存而不触发此错误? 3. 在Windows MSVC编译器中是否有类似问题?如何解决?
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值