【问题标题】:Symbol Lookup Error: Combining Executable and Library on 64bits符号查找错误:在 64 位上组合可执行文件和库
【发布时间】:2011-05-15 21:31:00
【问题描述】:

我想在一个使用可执行符号的库上创建一个 dlopen。我正在 64 位系统上编译 gdl-0.9,并且正在构建 gdl 将使用 dlopen 的库。问题是该库使用了可执行文件中的 gdl 代码,即使我使用了 -Wl,--export-dynamic 标志,程序也会崩溃并且印刷: gdl:符号查找错误:./two.so:未定义符号:_ZN4EnvT6NParamEj

这是我的做法:

将 two.cpp 编译为共享库 two.so。

// two.cpp
#include "envt.hpp"

using namespace std;

template< typename T>
BaseGDL* two_fun_template( BaseGDL* p0)
{
  T* p0C = static_cast<T*>( p0);
  T* res = new T( p0C->Dim(), BaseGDL::NOZERO);
  SizeT nEl = p0->N_Elements();
  for( SizeT i=0; i<nEl; ++i)
    {
      (*res)[ i] = 2 * ((*p0C)[ i]);
    }
  return res;
}

extern "C" BaseGDL* two_fun( EnvT* e)
{

  SizeT nParam=e->NParam();
  if (nParam != 1) {
    cout << "TWO: Improper Number of Variables" << endl;
    return new DLongGDL( -1);
  }

  BaseGDL* p0 = e->GetPar( 0);//, "TWO");

  if( p0->Type() == DOUBLE)
    return two_fun_template< DDoubleGDL>( p0);
  else if( p0->Type() == FLOAT)
    return two_fun_template< DFloatGDL>( p0);
  else 
    {
      return new DLongGDL( -1);
    }
}

使用“Ubuntu 10.04.1 LTS”预构建的 gdl。

$ gdl
GDL - GNU Data Language, Version 0.9
For basic information type HELP,/INFO
'GDL_STARTUP'/'IDL_STARTUP' environment variables both not set.
No startup file read.
GDL> linkimage,'TWO','./two.so',1,'two_fun'
GDL> print, "TWO Loaded"
GDL> print, two(1.0)
gdl: symbol lookup error: ./two.so: undefined symbol: _ZN4EnvT6NParamEj

所以我认为问题出在执行此行时:SizeT nParam=e->NParam();

接下来我拿到了gld-0.9源代码,用-Wl,--export-dynamic做了整个编译,同样的错误发生了。

接下来我使用 -m32 标志(强制 32 位)进行了整个编译,并且:

$ ../gdl32
GDL - GNU Data Language, Version 0.9
For basic information type HELP,/INFO
'GDL_STARTUP'/'IDL_STARTUP' environment variables both not set.
No startup file read.
GDL> linkimage,'TWO','./two.so',1,'two_fun'
GDL> print, "TWO Loaded"
GDL> print, two(1.0)
      2.00000
GDL>

所以我猜这意味着它是一个 64 位的问题,但为什么呢?我在网上搜索了很多,除了 -Wl,--export-dynamic 之外没有找到任何东西,也许我不知道怎么看或者其他的东西。有人可以帮忙吗?

顺便说一句,这是我在运行“nm”实用程序时得到的。

64 位:

$ nm two.so | grep NParam
                 U _ZN4EnvT6NParamEj
$ nm ../gdl64 | grep NParam
00000000006dc320 T _ZN4EnvT6NParamEy

32 位:

$ nm two.so | grep NParam
         U _ZN4EnvT6NParamEj
$ nm ../gdl32 | grep NParam
0830a6a0 T _ZN4EnvT6NParamEj

【问题讨论】:

  • 看起来你的头文件不同意编译库关于SizeT typedef的大小。具体来说,该库似乎使用 64 位返回值,two.so 需要 32 位。尝试运行从nmc++filt 的符号,看看jy 对应的确切类型。

标签: c++ linker 64-bit 32bit-64bit


【解决方案1】:

_ZN4EnvT6NParamEjEnvT::NParam(unsigned int)
_ZN4EnvT6NParamEyEnvT::NParam(unsigned long long)

因此,您应该首先查看如何包含 EnvT 的声明。您需要查看 NParam 的参数的类型并找到它的重新定义位置。

【讨论】:

  • 非常感谢您的帮助。
【解决方案2】:

我不知道你是否仍然可以使用帮助,但要编译这两个函数和所有其他函数为 64 位,你应该在 g++ 命令中添加 -DHAVE_64BIT_OS 选项。这样,预处理器在 typedefs.hpp 中为 SizeT 设置正确的类型。 所以编译将是

g++ -DHAVE_64BIT_OS -I/(gdl src的路径) -c two.cpp -fpic

所有其他命令保持不变。

【讨论】:

  • 我发现在人们指出类型差异之后。还是谢谢你。
【解决方案3】:

nm 的输出来看,类型似乎不同——可执行文件有_ZN4EnvT6NParamEy,而库需要_ZN4EnvT6NParamEj。如您所见,最后一个字母不同。

【讨论】:

  • 谢谢,我看到了区别,但不知道是什么
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-05-07
  • 2016-12-10
  • 2021-06-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-18
相关资源
最近更新 更多