3

我有一个重复调用 Delphi 函数的 Fortran 90 程序。该函数被多次调用,但最终程序因分段错误而退出。

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

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

DLL 是 32 位的,我正在使用 Windows 7 系统,使用具有规格的 32 位 gfortran 编译器:

COLLECT_GCC=C:\程序文件 (x86)\gcc\bin\gfortran.exe
COLLECT_LTO_WRAPPER=c:/程序文件 (x86)/gcc/bin/../libexec/gcc/i686-pc-mingw32/4.7.2/lto-wrapper.exe
目标:i686-pc-mingw32
配置:../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 --with-cloog=/home/ gfortran/gcc-home/binary/mingw32/native/x86_32/clog --with-gmp=/home/gfortran/gcc-home/binary/mingw32/native/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
线程型号:win32
gcc 版本 4.7.2 (GCC)

我之前曾发布过关于此代码的问题(请参阅从 Fortran 重复调用 C 函数时出现分段错误),但这只是第一个绊脚石。

我编译代码

>> gfortran -o cmod cmod.f90 -fbounds-check -ffree-line-length-none -dH -mrtd -g -L。线索.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 这样做。

4

1 回答 1

3

的存在borlandmm.dll表明您的任务几乎是不可能的。该DLL 用于允许不同的模块(例如可执行文件和DLL)共享一个通用的Delphi 内存管理器。这允许一个模块(例如可执行文件)分配一个 Delphi 字符串,并将其传递给另一个模块(例如 DLL),后者又可以释放该字符串。

除非两个模块共享同一个堆,否则这样的架构是行不通的。该borlandmm.dll库使跨模块的堆共享成为可能。任何希望使用其主机的 Delphi 内存管理器的 DLL 都包含该Sharemem单元,该单元反过来使用该borlandmm.dll库来实现内存管理器共享。

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

borlandmm.dll如果预期仅从 Delphi 主机调用此 DLL,则使用此 DLL 的设计是合理的。如果 DLL 的开发人员知道他们在做什么,那么他们就会知道该限制。您没有 DLL 的文档这一事实向我表明,您已经从另一个程序中提取了 DLL,并试图以未设计的方式使用它。你成功的机会非常低。

于 2013-05-22T05:40:49.927 回答