仅仅因为链接未使用的模块,怎么会在运行时发生段错误?

How can a segfault happen at runtime only because of linking unused modules?

我从内存分配语句中得到一个分段错误,只是因为我已经 link 将一些不相关的过程编辑到二进制文件中。

我有一个非常简单的Fort运行程序:

program whatsoever
!USE payload_modules

double precision,allocatable:: Vmat(:,:,:)

allocate(Vmat(2,2,2))
Vmat=1
write(*,*) Vmat
deallocate (Vmat)
! some more lines of code using procedures from payload_module
end program whatsoever

使用 gfortran whatsoever.f95 -o whatsoever 编译它会生成一个具有预期行为的程序。当然,这个程序不是打印八次1.000而是调用payload_modules,而是隐藏在注释中。但是,如果我编译并 link 带有发出

模块的程序
gfortran -c -g -fPIC -ffpe-trap=overflow -pedantic -fbounds-check \
    -fimplicit-none payload_module1.f90 payload_module2.f90 whatsever.f95

gcc -g -nostdlib -v -Wl,--verbose  -std=gnu99 -shared -Wl,-Bsymbolic-functions \
    -Wl,-z,relro -o whatsoever whatsoever.o payload_module1.o payload_module2.o

程序 whatsoever 不再 运行。我在分配语句中遇到分段错误。我还没有取消注释与模块相关的行(但是,取消注释会导致相同的行为)!

我知道有效负载模块的代码没有错误,因为我之前从 R 运行 它并将此工作代码包装到 f90 模块中。没有名称冲突;模块中没有任何内容被称为 Vmat。模块中只有一次对 allocate 的调用。它从来没有造成任何麻烦。仍然有足够的内存。 gdb 没有给我任何提示,需要内存地址。

linking 实际未调用的例程如何使程序崩溃?

使用

编译代码
gfortran whatsoever.f95 -o whatsoever

正在运行,因为您 link 针对系统库,一切就绪。这将对应于

gfortran whatsoever.f95 payload_module1.f90 payload_module2.f90 -o whatsoever

这也行。您使用的命令省略了系统库,并且代码在您第一次从那里调用函数时失败(分配)。您没有看到您缺少库,因为您创建了一个共享对象(稍后通常 link 针对库编辑)。

您选择分开编译对象并将它们link编译成可执行文件。使用 gcc 为 Fortran 程序执行此操作需要指定 Fortran 库,因此缺少 -lgfortran

我不确定编译选项的特定选择...-shared 通常用于库,您确定要共享二进制文件(不管是什么)吗? 使用 -nostdlib 告诉编译器不要 link 反对系统库。然后您需要指定那些库(您不需要)。

对于主程序test.F90和一个模块payload.F90,我运行

gfortran -c -g -fPIC -ffpe-trap=overflow -pedantic -fbounds-check \
   -fimplicit-none payload.F90 test.F90

gcc -g -v -Wl,--verbose  -std=gnu99 -Wl,-Bsymbolic-functions \
   -Wl,-z,relro -lgfortran -o whatsoever test.o payload.o

这可以正确编译和执行。

使用 gfortran 的高级选项可能更容易:

gfortran -g -fPIC -ffpe-trap=overflow -pedantic -fbounds-check \
  -fimplicit-none -Wl,-Bsymbolic-functions -Wl,-z,relro \
  payload.F90 test.F90 -o whatsoever

结果是一样的。