符号查找错误:在 64 位上组合可执行文件和库
我想在使用可执行文件符号的库上创建 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
I want to make a dlopen on a library that uses executable's symbols. I'm compiling gdl-0.9 on a 64bits system and I'm building a library that gdl will use dlopen. The problem is that the library uses gdl code which will be at the executable and, even though I used the -Wl,--export-dynamic flag, the program crashes and prints:
gdl: symbol lookup error: ./two.so: undefined symbol: _ZN4EnvT6NParamEj
Here is how I've done things:
Compiled two.cpp as the shared lib 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);
}
}
Used "Ubuntu 10.04.1 LTS" pre-build of 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
So I figured the problem was upon executing this line: SizeT nParam=e->NParam();
Next I got the gld-0.9 source code, did the whole compilation with -Wl,--export-dynamic and the same error occurred.
Next I did the whole compilation with -m32 flag (force 32bits) and:
$ ../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>
So I guess this means its a 64bit problem, but why? I've searched a lot in the web and didn't find anything other then the -Wl,--export-dynamic, maybe I didn't know how to look or something. Can anyone help?
Btw, this is what I get when running the "nm" util.
64bits:
$ nm two.so | grep NParam
U _ZN4EnvT6NParamEj
$ nm ../gdl64 | grep NParam
00000000006dc320 T _ZN4EnvT6NParamEy
32bits:
$ nm two.so | grep NParam
U _ZN4EnvT6NParamEj
$ nm ../gdl32 | grep NParam
0830a6a0 T _ZN4EnvT6NParamEj
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
_ZN4EnvT6NParamEj
是EnvT::NParam(unsigned int)
_ZN4EnvT6NParamEy
是EnvT::NParam(unsigned long long)
因此,您应该首先查看如何包含
EnvT
声明。您需要查看 NParam 参数的类型并找到它被重新定义的位置。_ZN4EnvT6NParamEj
isEnvT::NParam(unsigned int)
_ZN4EnvT6NParamEy
isEnvT::NParam(unsigned long long)
So you should start with looking at how you include declaration of
EnvT
. You need to look at what type of an argument of NParam and find where it's redefined.我不知道您是否仍然可以使用帮助,但是为了编译这两个函数以及所有其他 64 位函数,您应该在 g++ 命令中添加 -DHAVE_64BIT_OS 选项。这样,预处理器就可以在 typedefs.hpp 中为 SizeT 设置正确的类型。
因此编译将是
g++ -DHAVE_64BIT_OS -I/(path to gdl src) -c Two.cpp -fpic
所有其他命令保持不变。
I don't know if you still can use the help, but for compiling the the two function and all the others for 64 bit you should add -DHAVE_64BIT_OS option to the g++ command. This way the preprocessor sets the right type for SizeT in typedefs.hpp.
So compiling will be
g++ -DHAVE_64BIT_OS -I/(path to gdl src) -c two.cpp -fpic
All the other commands stay the same.
从
nm
输出看来,类型不同 - 可执行文件具有_ZN4EnvT6NParamEy
,而库需要_ZN4EnvT6NParamEj
。正如您所看到的,最后一个字母有所不同。From the
nm
output it looks like the types are different - the executable has_ZN4EnvT6NParamEy
while the library wants_ZN4EnvT6NParamEj
. As you can see the last letter differs.