当dlopen一个,它的符号没有被主符号覆盖,为什么?

时间:2014-12-07 04:25:28

标签: c linux compiler-errors ld

libp2.c

#include <stdio.h>
void pixman()
{
    printf("pixman in libp1\n");
}

libc2.c

#include <stdio.h>

void pixman();
void cairo()
{
    printf("cairo2\n");
    pixman();
}

的main.c

#include <stdio.h>
#include <dlfcn.h>


void pixman()
{
    printf("pixman in main\n");
}

int main()
{
    pixman();

    void* handle=NULL;
    void (*callfun)();

    handle=dlopen("/home/zpeng/test/so_test/libc2.so",RTLD_LAZY);
    callfun = (void(*)())dlsym(handle, "cairo");
    callfun();
...
}

编译

gcc -c  libp2.c -fPIC   -olibp2.o
rm libp2.a
ar -rs libp2.a libp2.o
gcc -shared -fPIC libc2.c  ./libp2.a -o libc2.so
gcc main.c  -ldl -L.  -g

结果:

pixman in main
cairo2
pixman: libp2

为什么最后一个不是“pixman in main”?

我看到符号处理(LD_DEBUG =符号),它以:

开头
21180:     symbol=pixman;  lookup in file=./a.out
21180:     symbol=pixman;  lookup in file=/lib64/libdl.so.2
21180:     symbol=pixman;  lookup in file=/lib64/tls/libc.so.6
21180:     symbol=pixman;  lookup in file=/lib64/ld-linux-x86-64.so.2
21180:     symbol=pixman;  lookup in file=/home/zpeng/test/so_test/libc2.so

如果我将-lc2或-rdynamic添加到gcc main cmd,它将生成:

pixman in main
cairo2
pixman in main

我的问题:

为什么在a.out中查找符号但没有得到结果并在没有-rdynamic和-lc2时继续搜索libc2.so?

2 个答案:

答案 0 :(得分:2)

为什么最后一个不是“pixman in main”? 那是因为共享库有自己的全局偏移表或GOT。当您在libc2.so中使用cairo函数时,将被调用的pixman函数与首先编译.so文件时解析的函数相同。

那是:

# creates object file only -- contains first pixman implementation
gcc -c  libp2.c -fPIC   -olibp2.o

# just turns the object file into an archive
ar -rs libp2.a libp2.o

# creates the .so file -- all symbols in libc2.c are resolved here 
# and you passed in the .a file for that purpose. The .a file containing the
# first pixman implementation gets put in libc2.so.
gcc -shared -fPIC libc2.c  ./libp2.a -o libc2.so  

在此之后,任何使用libc2.so的人都将获得存储在libc2.so中的副本。您发布的查找顺序是针对a.out我相信并且它是正确的。它在a.out中查找pixman,然后在libc2.so中查找,依此类推。

为什么在a.out中查找符号但没有得到结果并在没有-rdynamic和-lc2时继续搜索libc2.so rdynamic选项将所有符号加载到动态符号表 - 而不仅仅是它认为使用的符号表(lc2具有相同的效果)。当你加载所有这些符号时你就会发生冲突 - pixman函数。在这种情况下使用main.c实现。正如其他人所指出的那样,这可能会产生警告。

答案 1 :(得分:1)

您需要使用-fvisibility=hidden编译存档到.a文件中的源代码,以指示尽管它们是全局函数,但它们并不意味着在结果库之外使用,而是意味着解析库内的符号。这将导致.a文件中的符号与限定符&#34;一起显示。 t&#34;在nm -a而不是&#34; T&#34;,用于其他图书馆可用的符号。