从Fortran调用Delphi函数时出现分段错误

时间:2013-05-22 04:19:07

标签: delphi windows-7 32bit-64bit gfortran

我有一个Fortran 90程序,它反复调用Delphi函数。该函数被多次调用,但最终程序退出时出现分段错误。

我有一个用IBM fortran编译的代码的可执行文件,它运行得很好,我必须使用gfortran重新编译整个东西

我有主程序的源代码,但没有函数,它存在于随代码提供的DLL中,以及一个可能支持Delphi位的boreland DLL:borlndmm.dll

DLL是32位,我正在开发一个带有规格的32位gfortran编译器的Windows 7系统:

COLLECT_GCC=C:\program files (x86)\gcc\bin\gfortran.exe
COLLECT_LTO_WRAPPER=c:/program files (x86)/gcc/bin/../libexec/gcc/i686-pc-mingw32/4.7.2/lto-wrapper.exe
Target: i686-pc-mingw32
Configured with: ../gcc-4.7.2-mingw/configure --host=i686-pc-mingw32 --build=x86_64-unknown-linux-gnu --target=i686-pc-mi    ngw32 --prefix=/home/gfortran/gcc-home/binary/mingw32/native/x86_32/gcc/4.7.2 --with-gcc --with-gnu-as --with-gnu-ld --wi    th-cloog=/home/gfortran/gcc-home/binary/mingw32/native/x86_32/cloog --with-gmp=/home/gfortran/gcc-home/binary/mingw32/nat    ive/x86_32/gmp --with-mpfr=/home/gfortran/gcc-home/binary/mingw32/native/x86_32/mpfr --with-mpc=/home/gfortran/gcc-home/b    inary/mingw32/native/x86_32/mpc --enable-cloog-backend=ppl --with-sysroot=/home/gfortran/gcc-home/binary/mingw32/cross/x8    6_32/gcc/4.7.2 --disable-shared --disable-nls --disable-tls --disable-win32-registry --enable-libquadmath-support --enabl    e-libquadmath --enable-languages=c,c++,fortran --enable-libgomp --enable-threads=win32 --enable-lto --enable-static --ena    ble-shared=lto-plugin --enable-plugins --with-host-libstdcxx='-lstdc++ -lsupc++ -lm' --with-ppl=/home/gfortran/gcc-home/b    inary/mingw32/native/x86_32/ppl --enable-ld=yes
Thread model: win32
gcc version 4.7.2 (GCC)

我之前发布过有关此代码的问题(请参阅Segmentation fault when calling a C function from Fortran repeatedly),但这只是第一个绊脚石。

我用

编译代码
>> gfortran -o cmod cmod.f90  -fbounds-check -ffree-line-length-none -dH -mrtd -g -L. Clues.dll

但是当它失败时我甚至无法获得转储输出。 我在调用Delphi函数时遇到内存对齐问题,这最终导致我死亡。 或者我可能无法在64位系统上正确编译32位,我对此没有任何经验。 任何关于如何进行的想法都会受到欢迎。

IBM fortran的原始fortran代码中的函数定义是:

module overseer
 use kernel32
 interface
   function CluesOvr(scenario,region,soilorder,topography,rainfall,ASoildepth,Snumdairy,Snumsheep,Snumbeef,Snumdeer,AdditionalNitrogen,Supplementrate,SupplementType,Nloss,Ploss,ErrStr)
   !DEC$ ATTRIBUTES  VALUE :: scenario,region,soilorder,topography,rainfall,ASoildepth,Snumdairy,Snumsheep,Snumbeef,Snumdeer,AdditionalNitrogen,Supplementrate,SupplementType
   !DEC$ ATTRIBUTES  REFERENCE :: Nloss,Ploss,ErrStr
   LOGICAL CluesOvr
   integer*4 scenario,region,soilorder,topography,ASoildepth
   real*8 rainfall,Snumdairy,Snumsheep,Snumbeef,Snumdeer
   real*8 AdditionalNitrogen,Supplementrate
   Integer*4 SupplementType
   real*8 Nloss,Ploss
   character ErrStr(40)
   end function CluesOvr
 end interface
end module

我已翻译成:

INTERFACE
 LOGICAL (C_BOOL) FUNCTION CluesOvr(scenario,region,soilorder,topography,rainfall, &
    ASoildepth,Snumdairy,Snumsheep,Snumbeef,Snumdeer,AdditionalNitrogen, &
    Supplementrate, SupplementType,Nloss,Ploss, &
    ErrStr) BIND (C, name='CluesOvr')
    USE, INTRINSIC :: ISO_C_BINDING
    IMPLICIT NONE
    INTEGER (C_INT), INTENT(IN), VALUE :: scenario,region,soilorder,topography,ASoildepth
    REAL (C_DOUBLE), INTENT(IN), VALUE :: rainfall,Snumdairy,Snumsheep,Snumbeef,Snumdeer
    REAL (C_DOUBLE), INTENT(IN), VALUE :: AdditionalNitrogen,Supplementrate
    INTEGER (C_INT), INTENT(IN), VALUE :: SupplementType
    REAL (C_DOUBLE), INTENT(OUT) :: Nloss,Ploss
    CHARACTER(C_CHAR), INTENT(OUT) :: ErrStr(*)
  END FUNCTION CluesOvr
END INTERFACE

IBM代码也使用

 pointer (q,CluesOvr)
 p = loadlibrary("CluesOvr.dll")
 q = getprocaddress(p, "CluesOvr")

访问该功能。我不跟gfortran这样做。

1 个答案:

答案 0 :(得分:3)

borlandmm.dll的存在表明您的任务几乎不可能完成。该DLL用于允许不同的模块(例如可执行文件和DLL)共享公共Delphi内存管理器。这允许一个模块,可执行程序说,分配一个Delphi字符串,并将其传递给另一个模块,DLL说,这反过来可以解除分配字符串。

除非两个模块共享同一个堆,否则这样的架构无法工作。 borlandmm.dll库使得跨模块的堆共享成为可能。任何希望使用其主机的Delphi内存管理器的DLL都包含Sharemem单元,而borlandmm.dll单元又使用string库来实现内存管理器共享。

现在,您的Fortran主机无法满足所需的合同。唯一可以提供Delphi内存管理器的是Delphi主机。将要发生的是,您调用的DLL认为它负责释放传递的内存。 DLL可能接收堆分配的Delphi borlandmm.dll变量。当DLL尝试释放内存时,该内存已在Fortran主机进程中分配。这种不匹配很可能导致访问违规。每次调用该函数时都不一定会出现这些情况。

使用{{1}}的这个DLL的设计是合理的,前提是它只能从Delphi主机调用。如果DLL的开发人员知道他们在做什么,那么他们就会意识到这种限制。您没有DLL文档的事实向我建议您从另一个程序中提取DLL并尝试以未设计的方式使用它。你成功的机会非常低。