TypechoJoeTheme

MetMan's Blog

网站页面

Relocation truncated to fit链接错误解析

MetMan博 主
2023-10-21
/
0 评论
/
176 阅读
/
886 个字
/
百度已收录
10/21
本文最后更新于 2023年10月21日,已超过 335天没有更新。如果文章内容或图片资源失效,请留言反馈,我会及时处理,谢谢!

链接阶段有时会遇到relocation truncated to fit...错误。下面我们来探讨下原因及解决方法。

问题

  • 试验环境
$ cat /etc/redhat-release
CentOS Linux release 7.9.2009 (Core)
$ gfortran --version
GNU Fortran (GCC) 9.3.1 20200408 (Red Hat 9.3.1-2)

首先通过以下代码示例重现链接重定位错误。

program main
  implicit none
  integer,parameter :: nx = 1000, ny= 1000, nz =1000
  real,dimension(nx,ny,nz) :: arr_a,arr_b
  integer :: i,j,k

  arr_a = 3.0
  do k=1,nz
    do j=1,ny
      do i=1,nx
        arr_b(i,j,k) = arr_a(i,k,j) + i + j + k
      enddo
    enddo
  enddo
  print*, arr_b(1,2,3)
end

使用gfortran或ifort编译链接代码会出现如下错误信息:

$ gfortran -c relocation_error.f90 
$ gfotrtran -o test.exe relocation_error.o
或者
$ gfortran relocation_error.f90

链接时重定向错误:

relocation_error.f90:(.text+0x143): relocation truncated to fit: R_X86_64_32S against `.bss'
collect2: error: ld returned 1 exit status

原因探究

上面错误信息提到在地址.text+0x143链接重定向错误。

使用objdump工具查看目标文件汇编码

$ objdump -dzr relocation_error.o

根据错误信息中代码区位置(.text+0x143)定位汇编指令

Disassembly of section .text:

0000000000000000 <MAIN__>:
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
....
 13a:   f3 0f 58 c1             addss  %xmm1,%xmm0
 13e:   f3 0f 11 04 85 00 00    movss  %xmm0,0x0(,%rax,4)
 145:   00 00
                        143: R_X86_64_32S       .bss+0xee6b2800

地址13e指令movss %xmm0,0x0(,%rax,4)中0x0是占位符,链接重定向时会替换为下面的地址.bss+0xee6b2800

0xee6b2800转换为十进制为$4 \times10^{9}$,这个值恰好等于$1000\times1000\times1000\times4Bytes$,是数组arr_a的大小。

那么这里的.bss是什么?

下图是程序的抽象内存布局。通常程序执行的指令放在代码段(.text),而数据段存放的是程序中已经初始化且不为 0 的全局变量和静态变量。对于未初始化的全局变量和静态变量,因为编译器知道它们的初始值都是 0,因此便不需要再在程序的二进制映像中存放这么多 0 了,只需要记录他们的大小即可,这就是BSS 段。BSS 段这个缩写名字是 Block Started by Symbol,也称为Uninitalized data segment。.bss段通常不存在,直到程序加载执行,因此你对目标文件或可执行文件汇编分析时看不到.bss内容。.bss段有助于减少程序size和快速加载。

我们程序中arr_a和arr_b是未初始化的全局变量,会存放到.bss段中。

使用nm查看目标文件符号

$ nm relocation_error.o
0000000000000000 b arr_a.3868    # b代表bss
00000000ee6b2800 b arr_b.3870
                 U _gfortran_set_args
                 U _gfortran_set_options
                 U _gfortran_st_write
                 U _gfortran_st_write_done
                 U _gfortran_transfer_real_write
00000000000001c8 T main           # T/t 代表text代码段
0000000000000000 t MAIN__
0000000000000020 r options.4.3899

.bss段开启的符号是数组arr_a,而arr_b是从.bss开始ee6b2800开始。

为何.bss+0xee6b2800会出错?

因为GFortran和Ifort在x86_64上默认使用小代码内存模型,所有程序代码指令和静态分配的数据必须适应地址空间最低2GB地址(准确上限是比如2GB-2MB,因为任何程序地址空间最低2MB是永久不可用的)。0xee6b2800超出了2GB($2^{31}$)限制,导致.bss段不能放置变量。

如果在变量声明时加上初始化非0会如何?

real,dimension(nx,ny,nz) :: arr_a=1.0,arr_b=1.0

我这里试验会发现编译链接很慢,最终将/tmp空间塞满,因为编译器一直在往数据段写数据。

relocation_error.f90:16:0: fatal error: error writing to /tmp/ccOnHNs6.s: No space left on device

将数组维数设置小一点看看,比如nx=ny=nz=10

$ nm relocation_error.o
0000000000000000 d arr_a.1879        # d代表data数据端
0000000000000fa0 d arr_b.1881
                 U _gfortran_set_args
                 U _gfortran_set_options
                 U _gfortran_st_write
                 U _gfortran_st_write_done
                 U _gfortran_transfer_real_write
000000000000020e T main
0000000000000000 t MAIN__
0000000000000020 r options.4.1910

可以看出初始化为非0的变量存放到data数据段了。

解决方法

方法一

gfortran和ifort使用选项-mcmodel=medium即可解决该问题。

$ gfortran -mcmodel=medium relocation_error.f90

-mcmodel=mem_model告知编译器使用何种内存模型生成代码和数据区,该选项只用于x86_64架构,其中mem_model可以取以下几种值:

  • small 对于64位机器,编译器限制代码和数据区域在第一个2GB地址空间内,使用相对寻址方式访问代码和数据
  • medium 限制代码在第一个2GB地址空间内,但对数据不做内存限制。代码访问通过相对寻址方式,而数据访问需要通过绝对寻址方式
  • large 编译器对代码和数据区域都不做内存限制,通过绝对寻址方式访问。

IP(Instruction Pointer)相对寻址只需要32位,而绝对寻址需要64位,因此IP相对寻址快一些。

方法二

需要修改源代码,将大数组arr_a和arr_b改成动态分配数组,这样一来变量分配内存是放在堆(HEAP)区,没有限制。

real,allocatable,dimension(:,:,:) :: arr_a, arr_b

再次使用nm查看编译的目标文件,发现找不到全局变量符号arr_a及arr_b。

参考资料

  1. What does this GCC error "... relocation truncated to fit..." mean? | Newbedev
  2. What does this GCC error "... relocation truncated to fit..." mean?
  3. What do R_X86_64_32S and R_X86_64_64 relocation mean?
朗读
赞(0)
赞赏
感谢您的支持,我会继续努力哒!
版权属于:

MetMan's Blog

本文链接:

https://blog.metman.top/index.php/archives/26/(转载时请注明本文出处及文章链接)

评论 (0)

互动读者

标签云

最新回复

暂无回复

登录
X
用户名
密码