在G77编译的程序中混淆堆栈行为

时间:2014-09-06 22:41:52

标签: segmentation-fault fortran g77

我有一个C ++和Fortran 77的混合体,都是用G77编译的。 它主要是C ++,但它调用ODE求解器DVERK,然后回调到全局C函数以获得导数(用__stdcall声明)。 它一切正常,直到我得到一个奇怪的SIGSEGV。

我追踪到了这一点,这是因为esp正在减少其分段边界以下。 这样做的原因是DVERK包含**运算符,它在内部是一个函数调用,具有两个由栈上的值传递的双精度值,为16个字节。 该函数返回答案,但后来我看到了这条指令:

sub 0x10,%esp

将堆栈指针递减16个字节,好像它将参数放回堆栈(?) G77似乎在每次调用函数后执行此操作,并且通常它没有任何危害,因为堆栈指针未更改。 但是,在**的情况下,堆栈指针保持递减,如果该代码执行了足够的次数,则递减直到我得到SIGSEGV。 (如果有足够的堆栈空间,则不会出现此问题,因为DVERK的返回会将其清除。)

我尝试用a**b替换代码dexp(dlog(a)*b),但同样的事情发生了,除了它发生在两个步骤中,dlog之后的8个字节和{{1}之后的8个字节}。

在设置G77与其运行时库使用的调用约定时,我必须做错。 专业知识赞赏。

1 个答案:

答案 0 :(得分:2)

在这个时代,将C或C ++与Fortran混合的方法是使用ISO-C_Binding。从C ++开始,使用extern C调用。在Fortran中使用(英语单词)Fortran ISO C Binding用于调用的过程。这将导致Fortran使用C的调用约定(ABI)。然后您不必了解编译器内部。为此,您必须使用比g77更现代的Fortran编译器,例如gfortran。 gfortran完全能够编译FORTRAN 77.正式的ISO-C-Binding是Fortran 2003的一部分 - 你可以在C ++和现有的FORTRAN 77之间编写一个包装器。

有一个Stackoverflow标记解释了ISO-C-Binding:https://stackoverflow.com/tags/fortran-iso-c-binding/info