搞不定:GCC编译 动态库 例外捕获

发布于 2022-10-15 07:42:54 字数 4983 浏览 14 评论 0

最近遇到一个棘手的环境移植问题,原来的程序在AIX下运行没问题,但移植到LINUX(redhat)就有事,究其原因是如下两个要求无法同时达到:
  1)动态库与主程序同名全局变量拥有独立的地址(即指向不同的内存)
  2)在动态库或主程序中能捕获对方抛出的例外
不知道用什么样的GCC选项能做到!?

以下是我的测试程序:

---- exception.h ----

  1. class CError
  2. {
  3. };

复制代码---- libf1.cpp ----

  1. #include "exception.h"
  2. #include <stdio.h>
  3. struct XMe {
  4.   void (* ff)(void);
  5. };
  6. char * ppp = NULL; // 全局变量,由主程序赋值
  7. XMe * pMe = NULL;
  8. extern "C" void f1() {
  9.     printf("libf1: %X, %s\n", &ppp, ppp); // 打印下自己的地址和值
  10.     try {
  11.        pMe->ff();
  12.     } catch (CError & e) {
  13.        printf("f1: catch CError from main.\n"); // 接获主程序的例外
  14.     } catch (...) {
  15.        printf("f1: catch unknown exception from main.\n"); // 无法探查出主程序是何例外
  16.     }
  17.     printf("f1: throw CError ... \n");
  18.     throw CError(); // 抛出例外
  19. }

复制代码---- main.cpp ----

  1. #include <iostream>
  2. #include <dlfcn.h>
  3. #include "exception.h"
  4. using namespace std;
  5. char * ppp = "I am main"; // 全局变量,同名的
  6. static char * libf1 = "YOU!!!";
  7. void f0 () {
  8.    throw CError();
  9. }
  10. struct XMe {
  11.    void (* ff)(void);
  12. };
  13. XMe me = {f0};
  14. main() {
  15.     // 这一段是证明在本模块内,例外抛出和接获都正常
  16.     try {
  17.             f0();
  18.     } catch (CError& e) {
  19.             cout << "f0: CError. " << endl;
  20.     } catch (...) {
  21.             cout << "f0: unknown exception - expected: CError. " << endl;
  22.     }
  23.     // 以下开始测试主程序与动态库之间的交互
  24.     void *lib_f1;
  25.     void (*f1_call)();
  26.     char ** p4libf1 = NULL;
  27.     XMe ** p4libf1me = NULL;
  28.     if (!(lib_f1=dlopen("./libf1.so",RTLD_LAZY))) { // 打开动态库
  29.             cout << "Can't open ./libf1.so." << endl;
  30.             exit(1);
  31.     }
  32.     if (!(f1_call=(void (*)())dlsym(lib_f1,"f1"))) { // 定位到函数f1
  33.             cout << "Can't bind f1." << endl;
  34.             exit(2);
  35.     }
  36.     if ((p4libf1me=(XMe **)dlsym(lib_f1,"pMe"))) { // 定位到全局变量pMe
  37.            *p4libf1me = &me; // 把主程序的函数赋予他
  38.     }
  39.     if ((p4libf1=(char **)dlsym(lib_f1,"ppp"))) { // 定位到全局变量ppp
  40.            *p4libf1 = libf1; // 把主程序的某个不同于自己的ppp的地址赋予他
  41.     }
  42.     printf("main0: %X, %s\n", &ppp, ppp); // 打印自己
  43.     try {
  44.             (*f1_call)(); // 调用动态库的函数
  45.     } catch (CError& e) {
  46.             cout << "f1: CError." << endl;
  47.     } catch (...) {
  48.             cout << "f1: unknown exception - expected: CError. " << endl;
  49.     }
  50.     dlclose(lib_f1);
  51. }

复制代码---- makefile ----

  1. CC = g++
  2. all: main libf1.so
  3. main: main.cpp exception.h
  4. # 这样例外才能正确接获(so和main之间)
  5.         $(CC) -Wl,-E -g -ldl -o test_exception test_exception.cpp
  6. # 这样才能让同名全局变量指向不同地址(so和main之间)
  7. #        $(CC) -g -ldl -o test_exception test_exception.cpp
  8. # 然而,鱼和熊掌不可兼得,咋办?
  9. libf1.so: libf1.cpp exception.h
  10.         $(CC) -g -shared -o libf1.so libf1.cpp
  11. clean:
  12.         rm -f *.o libf?.so core* a.out main

复制代码

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文