64位gcc代码中的32位指针溢出 - 编译失败

时间:2015-06-17 22:10:34

标签: pointers gcc compiler-errors fortran gfortran

我正在运行Yosemite的Mac(2.2 GHz Intel Core i7)上使用gFortran编译一个非常大的传统Fortran 90代码(screamer)。 (gFortran V5.1.0)我有16 GB的RAM。代码是内存密集型的,我正在尝试增加数组大小以解决更大的问题。我维护了大约10年的代码,现在重写200,000行代码不是一种选择。当我通过改变整数“max_nodes”小心地增加2-D矩阵(am(max_nodes,max_nodes))和几个1-D向量(RHS(max_nodes)和a(max_nodes * 2))的大小时,我最终得到编译期间32位指针限制(4字节无符号整数限制)。见下文。

最终部分布局:

__TEXT/__text addr=0x100001390, size=0x0006B9CB, fileOffset=0x00001390, type=1
__TEXT/__text_startup addr=0x10006CD60, size=0x00000041,    fileOffset=0x0006CD60, type=1
__TEXT/__text_exit addr=0x10006CDB0, size=0x00000031, fileOffset=0x0006CDB0, type=1
__TEXT/__stubs addr=0x10006CDE2, size=0x00000252, fileOffset=0x0006CDE2, type=28
__TEXT/__stub_helper addr=0x10006D034, size=0x000003EE, fileOffset=0x0006D034, type=32
__TEXT/__cstring addr=0x10006D428, size=0x0000CFCB, fileOffset=0x0006D428, type=13
__TEXT/__const addr=0x10007A400, size=0x00008F00, fileOffset=0x0007A400, type=0
__TEXT/__eh_frame addr=0x100083300, size=0x0000DCF8, fileOffset=0x00083300, type=19
__DATA/__got addr=0x100091000, size=0x00000060, fileOffset=0x00091000, type=29
__DATA/__nl_symbol_ptr addr=0x100091060, size=0x00000010, fileOffset=0x00091060, type=29
__DATA/__la_symbol_ptr addr=0x100091070, size=0x00000318, fileOffset=0x00091070, type=27
__DATA/__mod_init_func addr=0x100091388, size=0x00000010,  fileOffset=0x00091388, type=33
__DATA/__mod_term_func addr=0x100091398, size=0x00000008, fileOffset=0x00091398, type=34

__DATA/__const addr=0x1000913A0, size=0x000007C8, fileOffset=0x000913A0, type=0
__DATA/__static_data addr=0x100091B68, size=0x00000003, fileOffset=0x00091B68, type=0
__DATA/__data addr=0x100091B80, size=0x000003E0, fileOffset=0x00091B80, type=0
__DATA/__bss4 addr=0x100091F60, size=0x00000018, fileOffset=0x00000000, type=25
__DATA/__bss5 addr=0x100091F80, size=0x00020000, fileOffset=0x00000000, type=25
__DATA/__bss3 addr=0x1000B1F80, size=0x00000028, fileOffset=0x00000000, type=25
__DATA/__pu_bss2 addr=0x1000B1FA8, size=0x00000008, fileOffset=0x00000000, type=25
__DATA/__bss2 addr=0x1000B1FB0, size=0x00000024, fileOffset=0x00000000, type=25
__DATA/__pu_bss5 addr=0x1000B1FE0, size=0x0000024C, fileOffset=0x00000000, type=25
__DATA/__pu_bss4 addr=0x1000B2230, size=0x00000018, fileOffset=0x00000000, type=25
__DATA/__common addr=0x1000B2260, size=0x000020D8, fileOffset=0x00000000, type=25
__DATA/__zo_bss3 addr=0x1000B4338, size=0x00000021, fileOffset=0x00000000, type=25
__DATA/__huge addr=0x1000B4360, size=0x984EB80C, fileOffset=0x00000000, type=25

ld:32位RIP相对引用超出范围(2147639505 max is +/- 4GB):从_main_loop_(0x10000E120)到_a.4206(0x180034380),来自screamer64.a(main_loop.o)的'_main_loop_'架构x86_64 collect2:错误:ld返回1退出状态

在此错误消息中,main_loop是screamer中的核心求解器子例程,用于填充和求解大型矩阵。在这个子程序中,定义了大的实数* 8矩阵和实数* 8矢量。

此注册指令指针(RIP)错误在Web上多次被注意到。到目前为止,这些可用的信息并没有帮助我解决我的问题。注意:带符号的4字节整数限制为2,147,483,647,因此错误似乎与使用32位指针直接相关。

gFortran编译器选项包括-mcmodel = medium,它应该将指针指向64位。 -m64无效。达到指针限制时,主矩阵和向量使用的总内存大于2.4 GB。令人困惑的是代码完全是64位,所以我没想到32位指针。请参阅下面的64位检查。

rbspielman $ file screamer64

screamer64:Mach-O 64位可执行文件x86_64

主矩阵和向量都是实数* 8(64位)。所有大型数组都直接在这个子例程中声明,并且不是共同的。

所有其他共同变量按大小排序。 real * 8,real,int,char。

简单的测试程序表明没有基本的内存限制。我可以轻松地将静态数组定义为> 10 GB没有问题。较大的阵列也可以工作,但最终会使用虚拟内存并按预期减速。

显然存在某种内存或指针大小限制,但我无法弄明白。代码矩阵解算器是庞大的,更现实的测试程序将是乏味的。

(我也在Ubuntu LINUX中编译screamer,没有问题,直到与Mac相同的数组限制.Windows 8中的编译在通常的2 GB内存限制下失败,而不是指针限制。)

建议将不胜感激。

1 个答案:

答案 0 :(得分:0)

我在运行10.11.5的Mac上遇到了与GNU Fortran(GCC)5.1.0相同的问题,但OP提供的解决方案对我不起作用。

然而,我确实找到了一个解决方案:在系统地修剪了我相当行人的遗留代码之后,我发现每个数组都必须明确填充某些内容。您无法在代码中填写它。我知道这听起来很愚蠢,但是一旦我初步确定每个"真实的"在我做任何I / O或其他工作之前,数组(32位,它是遗留代码)有0.0,它没有任何抱怨地链接。

而且,是的,和OP一样,我的代码一直工作,直到我改变了数组的大小。

这个工作的原因可能在于此错误报告的内容:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63793但我不能告诉您如何提出更好的解决方法。我唯一的猜测是,在开头初始化每个数组都有利于GOT而不是RIP。 (什么时候会修复?我只是不知道如何推动这个问题并且错误报告的日期是2014-11-09)