【发布时间】:2012-04-26 04:24:11
【问题描述】:
对 Fortran .dll 使用相同的源文件,我可以使用 Compaq Visual Fortran 6.6C 或 Intel Visual Fortran 12.1.3.300 (IA-32) 编译它们。问题是在 Intel 二进制文件上执行失败,但在 Compaq 上运行良好。我在 Windows 7 64 位系统上编译 32 位。 .dll调用驱动写在C#中。
当调用内部子例程(从 .dll 入口例程调用)时,失败消息来自可怕的_chkstk() 调用。 (所以回答chkstk())
有问题的过程被声明为(请原谅固定的文件格式)
SUBROUTINE SRF(den, crpm, icrpm, inose, qeff, rev,
& qqmax, lvtyp1, lvtyp2, avespd, fridry, luin,
& luout, lurtpo, ludiag, ndiag, n, nzdepth,
& unit, unito, ier)
INTEGER*4 lvtyp1, lvtyp2, luin, luout, lurtpo, ludiag, ndiag, n,
& ncp, inose, icrpm, ier, nzdepth
REAL*8 den, crpm, qeff, rev, qqmax, avespd, fridry
CHARACTER*2 unit, unito
并像这样调用:
CALL SRF(den, crpm(i), i, inose, qeff(i), rev(i),
& qqmax(i), lvtyp1, lvtyp2, avespd, fridry,
& luin, luout, lurtpo, ludiag, ndiag, n, nzdepth,
& unit, unito, ier)
除了crpm、qeff、rev 和qqmax 之外,具有类似变量规范的数组是每个SRF() 调用仅使用i-th 元素的数组。
如果参数的大小超过 8kb,我了解可能的堆栈问题,但在这种情况下,7 x real(64) + 11 x int(32) + 2 x 2 x char(8) = 832 bits 仅在传递的参数中。
我非常努力地将参数(尤其是数组)移动到模块中,但我一直收到同样的错误
.
Intel .dll 的反汇编是
Compaq .dll 的反汇编是
任何人都可以就导致 SO 的原因或如何调试它提供任何建议吗?
PS。我已将保留的堆栈空间增加到数百个Mb,但问题仍然存在。我尝试在反汇编程序中跳过chkstk() 调用,但程序崩溃了。堆栈检查从地址0x354000 开始,并向下迭代到0x2D2000,在该地址访问保护页时崩溃。栈底地址为0x282000。
【问题讨论】:
-
您在每种情况下都使用哪些编译器选项?尝试编译将所有你能想到的警告错误标志都启用。作为第一步,我倾向于将
-std -check all -Warn all,nodec,interfaces,declarations -gen_interfaces -g -C -traceback -fpe0 -fp-stack-check与 ifort 一起使用。 -
我希望您现在已经发现了自己的算术错误,但是您的 832 字节总数应该是 832 位。也并非总是这样,每个字符都由一个字节表示:这往往因编译器和平台而异。使用最新的编译器,各种“存储单元”的大小可以作为 ISO_FORTRAN_ENV 内部模块中定义的常量使用。
-
上面的两个 cmets 都给了我一些可以使用的东西。我会进行更多调查。可能存在
CVF没有捕获的堆栈损坏并且以某种方式将其吹倒。自从 80 年代首次编写代码以来,许多开发人员都接触过代码,代码中有很多内容。 -
作为更新,到目前为止我尝试过的所有技巧和更改都没有让我更接近解决方案。我已将参数的数量和大小减少到 8 个标量,但问题仍然存在。
-
_chkstk()检查是否有足够的堆栈空间用于局部变量,而不是参数(它们已经在堆栈中)。您是否偶然在子程序本地有大型数组?默认情况下,英特尔 Fortran 不对本地数组进行堆分配。
标签: arguments fortran intel-fortran