我有一个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这样做。
答案 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并尝试以未设计的方式使用它。你成功的机会非常低。