gpt4 book ai didi

c++ - 从 C++ 拦截 Fortran STOP

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:55:11 25 4
gpt4 key购买 nike

我准备了一个旧版 Fortran 库的 C++ 接口(interface)。

遗留库中的一些子例程遵循丑陋但可用的状态代码约定来报告错误,我使用此类状态代码从我的 C++ 代码中抛出一个可读的异常:它工作得很好。

另一方面,有时遗留库调用STOP(终止程序)。即使病情是可以恢复的,它也经常这样做。

我想从 C++ 中捕获这个STOP,到目前为止我还没有成功。

下面的代码很简单,但恰好代表了手头的问题:

Fortran 遗留库 fmodule.f90:

module fmodule
use iso_c_binding
contains
subroutine fsub(x) bind(c, name="fsub")
real(c_double) x
if(x>=5) then
stop 'x >=5 : this kills the program'
else
print*, x
end if
end subroutine fsub
end module fmodule

C++ 接口(interface)main.cpp:

#include<iostream>

// prototype for the external Fortran subroutine
extern "C" {
void fsub(double& x);
}

int main() {
double x;
while(std::cin >> x) {
fsub(x);
}
return 0;
}

编译行(GCC 4.8.1/OS X 10.7.4;$ 表示命令提示符):

$ gfortran -o libfmodule.so fmodule.f90 -shared  -fPIC -Wall
$ g++ main.cpp -L. -lfmodule -std=c++11

运行:

$ ./a.out 
1
1.0000000000000000
2
2.0000000000000000
3
3.0000000000000000
4
4.0000000000000000
5
STOP x >=5 : this kills the program

我如何捕获 STOP 并请求另一个号码。请注意,我不想触及 Fortran 代码

我尝试过的:

  • std::atexit:一旦我输入它就不能从它“回来”
  • std::signal:STOP 似乎没有发出我可以捕获的信号

最佳答案

您可以通过拦截 Fortran 运行时对 exit 函数的调用来解决您的问题。见下文。 a.out 是用您的代码和您提供的编译行创建的。

第 1 步。确定调用了哪个函数。启动 gdb

$ gdb ./a.out
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-60.el6_4.1)
[...]
(gdb) break fsub
Breakpoint 1 at 0x400888
(gdb) run
Starting program: a.out
5

Breakpoint 1, 0x00007ffff7dfc7e4 in fsub () from ./libfmodule.so
(gdb) step
Single stepping until exit from function fsub,
which has no line number information.
stop_string (string=0x7ffff7dfc8d8 "x >=5 : this kills the programfmodule.f90", len=30) at /usr/local/src/gcc-4.7.2/libgfortran/runtime/stop.c:67

所以调用了stop_string。我们需要知道这个函数对应于哪个品种。

第 2 步。找到 stop_string 函数的确切名称。它必须在共享库之一中。

$ ldd ./a.out 
linux-vdso.so.1 => (0x00007fff54095000)
libfmodule.so => ./libfmodule.so (0x00007fa31ab7d000)
libstdc++.so.6 => /usr/local/gcc/4.7.2/lib64/libstdc++.so.6 (0x00007fa31a875000)
libm.so.6 => /lib64/libm.so.6 (0x0000003da4000000)
libgcc_s.so.1 => /usr/local/gcc/4.7.2/lib64/libgcc_s.so.1 (0x00007fa31a643000)
libc.so.6 => /lib64/libc.so.6 (0x0000003da3c00000)
libgfortran.so.3 => /usr/local/gcc/4.7.2/lib64/libgfortran.so.3 (0x00007fa31a32f000)
libquadmath.so.0 => /usr/local/gcc/4.7.2/lib64/libquadmath.so.0 (0x00007fa31a0fa000)
/lib64/ld-linux-x86-64.so.2 (0x0000003da3800000)

我在 fortran 运行时中(毫不奇怪)找到了它。

$ readelf -s /usr/local/gcc/4.7.2/lib64/libgfortran.so.3|grep stop_string
1121: 000000000001b320 63 FUNC GLOBAL DEFAULT 11 _gfortran_stop_string@@GFORTRAN_1.0
2417: 000000000001b320 63 FUNC GLOBAL DEFAULT 11 _gfortran_stop_string

第 3 步。编写将替换该函数的函数

我在源代码(/usr/local/src/gcc-4.7.2/libgfortran/runtime/stop.c see gdb session )

$ cat my_exit.c 
#define _GNU_SOURCE
#include <stdio.h>

void _gfortran_stop_string (const char *string, int len)
{
printf("Let's keep on");
}

第 4 步。编译导出该符号的共享对象。

gcc -Wall -fPIC -c -o my_exit.o my_exit.c
gcc -shared -fPIC -Wl,-soname -Wl,libmy_exit.so -o libmy_exit.so my_exit.o

第 5 步。使用 LD_PRELOAD 运行程序,以便我们的新函数优先于运行时的函数

$ LD_PRELOAD=./libmy_exit.so ./a.out 
1
1.0000000000000000
2
2.0000000000000000
3
3.0000000000000000
4
4.0000000000000000
5
Let's keep on 5.0000000000000000
6
Let's keep on 6.0000000000000000
7
Let's keep on 7.0000000000000000

给你。

关于c++ - 从 C++ 拦截 Fortran STOP,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19596375/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com