【问题标题】:Pointer is being being masked when calling a C function from Fortran从 Fortran 调用 C 函数时,指针被屏蔽
【发布时间】:2019-06-19 21:29:49
【问题描述】:

TL;DR

当我将数组从 Fortran 传递到 C 时,数组的地址在 C 中不正确。我通过在 CALL 之前打印 Fortran 中数组的地址来检查这一点,然后进入 C 函数并打印参数的地址。

  • Fortran 指针:0x9acd44c0
  • C 指针:0xffffffff9acd44c0

C 指针的高位双字已设置为0xffffffff。我试图理解为什么会发生这种情况,并且只发生在 HPC 集群上,而不是在开发机器上。

上下文

我正在使用一个用 Fortran/C++/CUDA 编写的相当大的科学程序。在某些特定机器上,从 Fortran 调用 C 函数时出现段错误。我发现一个指针被传递给 C 函数,其中一些字节设置不正确。

代码片段

程序中的每个 Fortran 文件都包含一个通用头文件,该头文件设置一些选项并声明通用块。

IMPLICIT REAL*8  (A-H,O-Z)
COMMON/NBODY/  X(3,NMAX), BODY(NMAX)
COMMON/GPU/    GPUPHI(NMAX)

Fortran 调用站点如下所示:

CALL GPUPOT(NN,BODY(IFIRST),X(1,IFIRST),GPUPHI)

nvcc编译的C函数声明如下:

extern "C" void gpupot_(int *n,
                       double m[],
                       double x[][3],
                       double pot[]);

GDB 输出

调试发现pot的指针值不对;因此任何访问该数组的尝试都会出现段错误。

当我使用 gdb 运行程序时,我在调用 gpupot 之前放置了一个断点并打印了 GPUPHI 变量的值:

(gdb) p &GPUPHI   
$1 = (PTR TO -> ( real(kind=8) (1050000))) 0x9acd44c0 <gpu_>

然后我让调试器进入gpupot_ C 函数,并检查pot 参数的值:

(gdb) p pot
$2 = (double *) 0xffffffff9acd44c0

所有其他参数都有正确的指针值。

编译器选项

gfortran 设置的编译器选项是:

 -fPIC -O3 -ffast-math -Wall -fopenmp -mcmodel=medium -march=native -mavx -m64  

nvcc 正在使用以下内容:

-ccbin=g++ -Xptxas -v -ftz=true -lineinfo -D_FORCE_INLINES \
-gencode arch=compute_35,code=sm_35 \
-gencode arch=compute_35,code=compute_35 -Xcompiler \
"-O3 -fPIC -Wall -fopenmp -std=c++11 -fPIE -m64 -mavx \
-march=native" -std=c++14 -lineinfo 

对于调试,-O3 被替换为 -g -O0 -fcheck=all -fstack-protector -fno-omit-frame-pointer,但行为(崩溃)保持不变。

【问题讨论】:

  • 您可能必须关闭优化(并添加-g)以确保在您进入gnupot_ 时检查pot 的正确值。否则,当它被传递给gnupot_ 时,您似乎得到了GPUPHI 的[不需要的] 符号扩展名。您可以在调用之前打印地址(在fortran 中)。并且,让gnupot_ 使用%p 对他们执行printf。那么其他指针值呢——它们是否有同样的问题,或者它只是[似乎]在 GPU 内存中的那个?猜测一下,-mcmodel=medium 可能是个问题,因为它在 fortran 中而不是 C
  • 程序符号映射说明了什么(例如readelf -s的输出)?使用-mcmodel=medium,大多数小符号链接到 2GB 以下,但较大的符号链接到 2GB 以上(这意味着设置了符号位)。
  • @CraigEstey 我已更新问题以显示我的调试选项。其他指针值很好;只是pot 不好。它实际上不在 GPU 内存中,它是一个普通的 fortran 数组。
  • 做(例如)readelf -s ./myexec | less。在.symtab 部分,查看GPUPHI [和您传递的其他人] 的地址。 GPUPHI 的地址是否完全不同?我认为您应该与-mcmodel保持一致。没有它你能建造吗?这有帮助吗?你能读 x86 asm 吗?如果是这样,您可以在 fortran 例程中反汇编 call 以确保它不会生成符号扩展的指令。 fortran 代码是否知道它正在调用 C/C++ 例程(例如,fortran 是否具有用于 func 声明的“extern C”等效项)?
  • 很高兴您修复了它。这是一个很好的参考资料,可能会有所帮助:gcc.gnu.org/onlinedocs/gcc-4.9.4/gfortran.pdf 第 7.1 节是关于互操作性的,第 7.1.4 节是关于子例程调用声明/约定的

标签: c cuda fortran


【解决方案1】:

这是由我的顶级 cmets [和你的] 作为序言的。

您似乎收到了地址的 [不需要的] 符号扩展。

gfortran 正在使用 -mcmodel=medium 构建,但 C 没有。

使用该选项,更大的符号/数组将链接到 2GB 以上 [已设置符号位]

因此,为两者添加选项或将其全部关闭以解决问题。

【讨论】:

    猜你喜欢
    • 2016-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-29
    • 2012-12-17
    • 1970-01-01
    • 2010-12-08
    • 1970-01-01
    相关资源
    最近更新 更多