仅仅因为链接未使用的模块,怎么会在运行时发生段错误?
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
结果是一样的。
我从内存分配语句中得到一个分段错误,只是因为我已经 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
结果是一样的。