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



我正在运行优胜美地的Mac(2.2 GHz Intel Core i7)上使用gFortran编译一个非常大的遗留Fortran 90代码(尖叫者)。(gFortran V5.1.0)我有 16 GB 的内存。代码是内存密集型的,我正在尝试增加数组大小以解决更大的问题。我已经维护了代码>10 年,现在重写 200,000 行代码不是一种选择。当我通过改变整数"max_nodes"来小心地增加二维矩阵(am(max_nodes,max_nodes))和几个一维向量(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最大值为 +/-4GB):从 _main_loop_ (0x10000E120) 到 _a.4206 (0x180034380) 来自 screamer64.a(main_loop.o) 的"_main_loop_",用于架构x86_64collect2:错误: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

尖叫64:Mach-O 64位可执行x86_64

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

所有其他共同变量按大小排序。 实数*8,实数,整数,字符。

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

显然有某种内存或指针大小限制,但我只是无法弄清楚。代码矩阵求解器非常庞大,更现实的测试程序将很乏味。

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

如能提出建议,将不胜感激。

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

然而,我

确实找到了一个解决方案:在系统地修剪了我相当普通的遗留代码后,我发现每个数组都必须显式填充一些东西。您无法开始在代码中填充它。我知道这听起来很愚蠢,但是一旦我在做任何 I/O 或其他工作之前用 0.0 初始化了每个"真实"数组(32 位,它是遗留代码),它就会毫无怨言地链接。

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

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

相关内容

  • 没有找到相关文章

最新更新