使用Fortran .dll的相同源文件,我可以使用Compaq Visual Fortran 6.6C或Intel Visual Fortran 12.1.3.300(IA-32)编译它们。问题是英特尔二进制文件的执行失败,但与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
之外,具有类似的变量规范是每个{{{}仅使用i-th
个元素的数组1}}来电。
如果参数的大小超过SRF()
,我理解可能的堆栈问题,但在这种情况下,我们只在传递的参数中有8kb
。
我已经非常努力地将参数(尤其是数组)移动到模块中,但我一直得到同样的错误
来自 Intel .dll的解散
来自 Compaq .dll的
任何人都可以就导致SO的原因或如何调试提供任何建议吗?
PS。我已将保留的堆栈空间增加到数百7 x real(64) + 11 x int(32) + 2 x 2 x char(8) = 832 bits
,问题仍然存在。我试过跳过dissasembler中的Mb
调用但是崩溃了程序。堆栈检查从地址chkstk()
开始,并向下迭代到0x354000
,在那里崩溃访问保护页面。堆栈底部地址为0x2D2000
。
答案 0 :(得分:3)
你正在射击信使。 Compaq生成的代码也调用_chkstk(),区别在于它内联它。一个常见的优化。两个片段之间的主要区别是:
mov eax, 0D3668h
VS
sub esp, 233E4h
您在此处看到的值是函数所需的堆栈空间量。英特尔代码需要0xd3668字节= 865869字节。 Compaq代码需要0x233e4 = 144356.差异很大。在这两种情况下,相当大的数量,但英特尔正在变得越来越重要,一个程序通常有一个兆字节的堆栈。吞噬它的0.86兆字节非常接近,嵌入了几个函数调用,你正在看这个网站的名字。
您需要了解的内容,我无法提供帮助,因为它不在您的代码段中,这就是英特尔生成的函数需要为其局部变量提供如此大空间的原因。解决方法是使用免费存储来查找大型数组的空间。或者使用链接器的/ STACK选项来请求更多的堆栈空间(猜测选项名称)。
答案 1 :(得分:0)
问题不在于发生堆栈溢出的函数调用。
在代码的早期,有一些全局矩阵被初始化并被放置在堆栈中,由于代码中的错误,它们仍然在范围内并且已经几乎填满了堆栈。当函数调用发生时,编译器试图将返回地址存储到堆栈中,结果导致程序崩溃。
解决方案是使全局矩阵 allocatable
并确保“堆数组”选项设置为适当的值。
这真是个兔子洞,当 100% 是我的错误代码导致了问题。