C++ Nm显示共享库中的符号,但链接时未定义符号

C++ Nm显示共享库中的符号,但链接时未定义符号,c++,macos,linker,linker-errors,amd-gpu,C++,Macos,Linker,Linker Errors,Amd Gpu,作为一种心理练习,我正在尝试编写一个程序,直接链接到我的MacBookPro的GPU驱动程序,而不是使用苹果的金属框架。经过一些探索,我找到了这个文件(可能是特定于我的特定硬件): 在其上运行文件可确认这是一个Mach-O 64位动态链接共享库。 在它上运行nm告诉我它是AMD的ROCr运行时的超集。我特别感兴趣的一个符号是: $ nm -gD AMDRadeonX6000MTLDriver | grep "hsa_init" 00000000001cca20 T __ZN3

作为一种心理练习,我正在尝试编写一个程序,直接链接到我的MacBookPro的GPU驱动程序,而不是使用苹果的金属框架。经过一些探索,我找到了这个文件(可能是特定于我的特定硬件):

在其上运行
文件
可确认这是一个Mach-O 64位动态链接共享库。 在它上运行
nm
告诉我它是AMD的ROCr运行时的超集。我特别感兴趣的一个符号是:

$ nm -gD AMDRadeonX6000MTLDriver | grep "hsa_init"
00000000001cca20 T __ZN3HSA8hsa_initEv
$ nm -gCD AMDRadeonX6000MTLDriver | grep "hsa_init"
00000000001cca20 T HSA::hsa_init()
所以我写了这个简单的程序(
rocr_test.cpp
):

并这样编译:

$ clang++ rocr_test.cpp -c
$ clang++ rocr_test.o /System/Library/Extensions/AMDRadeonX6000MTLDriver.bundle/Contents/MacOS/AMDRadeonX6000MTLDriver
Undefined symbols for architecture x86_64:
  "HSA::hsa_init()", referenced from:
      _main in rocr_main-95c854.o
ld: symbol(s) not found for architecture x86_64
clang-11: error: linker command failed with exit code 1 (use -v to see invocation)
但是,对象文件上的
nm
显示链接器应查找具有相同名称的符号:

$ nm rocr_test.o          
                 U __ZN3HSA8hsa_initEv
0000000000000000 T _main


nm
显示共享库中明显存在具有此确切名称的符号时,为什么我会看到此链接器错误?

如果
has_init
不是类的一部分,那么您仍然可以通过其损坏的名称调用函数。然而,只有当它是一个自由函数时,它才会起作用。如果它是类的一部分,那么在没有类定义的情况下就不能真正调用它,因为您不知道它对类成员做了什么,并且必须将对象作为第一个参数传递

#include <iostream>
#include <dlfcn.h>

using namespace std;

typedef int hsa_status_t;
typedef hsa_status_t (*hsa_init_t)();
hsa_init_t hsa_init;

const char *hsa_init_name = "__ZN3HSA8hsa_initEv";
const char *libPath = "/System/Library/Extensions/AMDRadeonX6000MTLDriver.bundle/Contents/MacOS/AMDRadeonX6000MTLDriver";

int main()
{
    void *libraryHandle = dlopen(libPath, RTLD_NOW);
    if (!libraryHandle)
    {
        cout << "Error opening library: " << libPath << " Error: " << dlerror() << endl;
        return 0;
    }
    dlerror(); // clear any existing error

    hsa_init = (hsa_init_t)dlsym(libraryHandle, hsa_init_name);
    if (!hsa_init)
    {
        cout << "Error importing symbol: " << hsa_init_name << " Error: " << dlerror() << endl;
        return 0;
    }

    hsa_init();

    return 0;
}
#包括
#包括
使用名称空间std;
输入hsa_状态的类型定义;
类型定义hsa_状态(*hsa_init_t)();
hsa_init_t hsa_init;
const char*hsa_init_name=“uu ZN3HSA8hsa_initEv”;
const char*libPath=“/System/Library/Extensions/AMDRadeonX6000MTLDriver.bundle/Contents/MacOS/AMDRadeonX6000MTLDriver”;
int main()
{
void*libraryHandle=dlopen(libPath,RTLD_NOW);
如果(!libraryHandle)
{

cout苹果的编译器有点不同,为了与库链接,它需要使用一个“.tbd”文件。这是一个文本文件,包含符号列表、UUID和它所链接的mach-O的基本细节。你可以在SDK中找到很多这样的例子(转到SDK根目录并找到。-键入f-name“*.tbd”)。TBD看起来像:

    --- !tapi-tbd-v3
archs:          [ x86_64 ]
uuids:          ['x86_64: 8891E6F5-0B7C-3CC7-88C1-9F5303311EC7' ]
platform:       ios
install-name:  /System/Library/Extensions/AMDRadeonX6000MTLDriver.bundle/Contents/MacOS/AMDRadeonX6000MTLDriver
objc-constraint:        none
exports:
  - archs:      [ x86_64 ]
    symbols:          [  __Z34amdMtl_GFX10_GetFallbackFamilyNameP15GFX10_HwInfoRec, __Z35amdMtl_GFX10_GetFallbackProductNameP15GFX10_HwInfoRec, __Z25amdMtl_GFX10_AllocLsHsMgrP15GFX10_MtlDeviceP14AMDPPMemMgrRec, ...

您必须为Bundle创建一个TBD(上面是使用jtool2--TBD创建的),并指导编译器使用它(或将它放在SDK目录中),这应该(希望如此)工作。

您是否检查了namemangling是否相同,因此它引用了相同的符号?或者它可能不是名称空间的一部分,而是一个类成员?这是一个很好的想法-看起来符号的名称是共享库中的
\uuuuzn3hsa8hsa_initEv
,并且我为我使用的名称空间中的函数获得了相同的符号名对类中的某个方法进行了。请不要向您添加包含有关该问题信息的问题的注释。编辑该问题并在其中添加此信息。您的注释说明了您在类中定义的函数,但该问题涉及在命名空间中定义的函数。请小心。我建议添加两个损坏名称“”的副本n问题“”。我希望在问题中显式地写下名称会对您有很大帮助。
rocr_test.o
是Mach-o格式还是ELF格式?使用
-v
选项运行链接器步骤是否提供了任何提示?嗯……这似乎也不起作用。奇怪的是,如果我编译到一个对象文件,我会看到确切的结果在对象文件和动态库中使用相同的符号名称。我对函数的签名很有信心,因为这与中定义的函数相匹配。苹果是否可能做了一些事情,使其无法/难以链接到ROCr运行时的分支?您是否也尝试在前面添加
bered,在这种情况下,您必须放置准确的符号?我自己也使用过这种方法,因此应该可以使用。您删除两个前导下划线中的一个似乎是正确的。如果我在链接之前生成一个对象文件,则表明您的代码生成了一个“未定义”符号,其名称与动态库导出的符号相同(即带有两个前导下划线)。因此,我怀疑问题与名称损坏或符号名称无关。可能还有其他原因?也可能是他们使用了不同的编译器,生成格式稍有不同的对象文件?因为该文件不应该由用户代码直接链接,这不会在规范中造成任何问题l case.我用gcc测试了它,现在它可以工作了。只是我没有删除前导的
,所以你可以试试:
\define hsa_init\uzn3hsa8hsa_initEv
。我想我记错了,因为调用它时,你需要确切的符号。前导的
只添加在导出的符号上,所以它应该被包括在内,并且在被调用时需要在场。很有趣!这似乎是个问题,尽管我很惊讶这会影响“标准”叮当声(我的系统上有这两个)还有GCC。我尝试通过自制软件安装jtool2,但
jtool2--tbd AMDRadeonX6000MTLDriver
似乎没有任何效果。如果我第一次使用
--analyze
运行,随后的操作会打印出13个错误,从
格式错误的行开始。你能更详细地描述一下你是如何生成tbd文件的吗?好的,我知道了能够使用Xcode工具链中的
tapi
实用程序生成TBD文件。现在我有了TBD文件,我如何“指导编译器使用它”?
#include <iostream>
#include <dlfcn.h>

using namespace std;

typedef int hsa_status_t;
typedef hsa_status_t (*hsa_init_t)();
hsa_init_t hsa_init;

const char *hsa_init_name = "__ZN3HSA8hsa_initEv";
const char *libPath = "/System/Library/Extensions/AMDRadeonX6000MTLDriver.bundle/Contents/MacOS/AMDRadeonX6000MTLDriver";

int main()
{
    void *libraryHandle = dlopen(libPath, RTLD_NOW);
    if (!libraryHandle)
    {
        cout << "Error opening library: " << libPath << " Error: " << dlerror() << endl;
        return 0;
    }
    dlerror(); // clear any existing error

    hsa_init = (hsa_init_t)dlsym(libraryHandle, hsa_init_name);
    if (!hsa_init)
    {
        cout << "Error importing symbol: " << hsa_init_name << " Error: " << dlerror() << endl;
        return 0;
    }

    hsa_init();

    return 0;
}
    --- !tapi-tbd-v3
archs:          [ x86_64 ]
uuids:          ['x86_64: 8891E6F5-0B7C-3CC7-88C1-9F5303311EC7' ]
platform:       ios
install-name:  /System/Library/Extensions/AMDRadeonX6000MTLDriver.bundle/Contents/MacOS/AMDRadeonX6000MTLDriver
objc-constraint:        none
exports:
  - archs:      [ x86_64 ]
    symbols:          [  __Z34amdMtl_GFX10_GetFallbackFamilyNameP15GFX10_HwInfoRec, __Z35amdMtl_GFX10_GetFallbackProductNameP15GFX10_HwInfoRec, __Z25amdMtl_GFX10_AllocLsHsMgrP15GFX10_MtlDeviceP14AMDPPMemMgrRec, ...