微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

C++中如何导入导出同名的不同函数

如何解决C++中如何导入导出同名的不同函数

我正在为自定义语言编写运行时库,但在使其在 Linux 下工作时遇到了一些问题。 我需要创建一个共享对象文件,该文件导出运行时规范指定的符号。 其中一些名称与标准库冲突,一些是无效的 C++ 标识符。

在 Windows 上,我可以简单地将模块定义文件传递给 MSVC 链接器,但 ld 似乎没有提供等效的解决方案。我已经阅读了一些关于链接器脚本的内容,发现它们提供了类似的功能,但它们只解决了部分问题。它们允许我更改不是有效 C++ 标识符的导出名称,但会导致标准库名称冲突的新问题。

例如,行 exit = _ZN7runtime4exitEi; 也会导致 imported 符号被替换,这会在调用 exit 时导致无限递归,最终导致段错误(我猜是退出的一种方式)。

库源(runtime.cpp):

#include <cstdlib>

namespace runtime {
    [[ noreturn ]] void __cdecl exit(int code) {
        ::exit(code);
    }

    // can't call this "not",because that's a keyword
    int __cdecl bitwise_not(int a) {
        return ~a;
    }
    
    // exported as "object::.ctor"
    void __cdecl object_ctor(runtime::object* instance) {
        // empty
    }
}

MSVC 模块定义(exports64.def):

LIBRARY runtime
EXPORTS
    exit=?exit@runtime@@YAXH@Z
    not=?bitwise_not@runtime@@YAHH@Z
    object::.ctor=?object_ctor@runtime@@YAXPEAUobject@1@@Z

链接脚本(libruntime64.map):

exit = _ZN7runtime4exitEi;
not = _ZN7runtime11bitwise_notEi
object::.ctor = _ZN7runtime11object_ctorEPNS_6objectE;

/* use the default linker script */
SECTIONS { } INSERT AFTER .text;

我尝试的另一种方法是使用 --wrapld 选项,但这不会更改导出的名称。使用以下代码传递 --wrap=exit 会将 __real_exit 正确解析为导入的 exit 函数,但导出的名称仍为 __wrap_exit

namespace runtime {
    extern "C" [[ noreturn ]] void __real_exit(int code);
    extern "C" [[ noreturn ]] void __wrap_exit(int code) {
        __real_exit(code);
    }
}

所以我想我的问题的核心是这样的:如何链接一个导入和导出两个同名不同符号的共享对象文件

如果这是相关的,我使用的前端是 Clang,完整的命令行如下所示:

clang -Wl,--script=runtime/libruntime64.map \
    -lstdc++ -lm -std=c++17 \
    -fpic -shared -Wl,-verbose \
    -o out/libruntime.so runtime/*.cpp

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。