7

使用 Fortran .dll 的相同源文件,我可以使用 Compaq Visual Fortran 6.6C 或 Intel Visual Fortran 12.1.3.300 (IA-32) 编译它们。问题是在 Intel 二进制文件上执行失败,但在 Compaq 上运行良好。我在 Windows 7 64 位系统上编译 32 位。.dll 调用驱动程序是用C#.

_chkstk()当调用内部子例程(从 .dll 入口例程调用)时,失败消息来自可怕的调用。(所以回答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和是数组,每次调用只使用其中的元素。qeffrevqqmaxi-thSRF()

如果参数超过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.

4

2 回答 2

3

你正在射击信使。Compaq 生成的代码调用 _chkstk(),不同之处在于它内联了它。常见的优化。这两个片段之间的主要区别是:

 mov eax, 0D3668h

对比

 sub esp, 233E4h

您在此处看到的值是函数所需的堆栈空间量。Intel 代码需要 0xd3668 字节 = 865869 字节。Compaq 代码需要 0x233e4 = 144356。差别很大。在这两种情况下,这都是相当大的数量,但英特尔的一个变得至关重要,一个程序通常有一个 1 兆字节的堆栈。吞下 0.86 兆字节的内容非常接近,嵌套了几个函数调用,您正在查看该站点的名称。

你需要找出什么,我无能为力,因为它不在你的代码片段中,这就是为什么英特尔生成的函数需要这么多空间来存放它的局部变量。解决方法是使用免费存储为大型数组寻找空间。或者使用链接器的 /STACK 选项来请求更多的堆栈空间(猜测选项名称)。

于 2012-06-09T18:32:23.773 回答
0

问题不在于发生堆栈溢出的函数调用。

在代码的早期,有一些全局矩阵被初始化并被放置在堆栈中,由于代码中的错误,它们仍在范围内并且几乎已经填满了堆栈。当函数调用发生时,编译器试图将返回地址存储到堆栈中,导致程序崩溃。

解决方案是制作全局矩阵allocatable,并确保“堆数组”选项设置为适当的值。

这真是个兔子洞,当它 100% 是我的错误代码导致问题时。

于 2021-05-05T16:50:04.670 回答