linux主文件和动态库之间变量和函数访问

通常我们需要从动态库里面直接调用可执行程序中的函数和变量,如果调用了-l选项,linux进程会自动把动态库的函数和变量加入到动态段中,所以直接访问是没有问题的。

我们这里要说的是非显示连接动态库,而是直接从c文件中通过dlopen函数打开动态库访问的方式,此时,gcc编译器不知道SO需要调用哪一个函数,所以不会讲函数放到动态段。故查找函数或者变量的时候,会出现找不到可执行程序中的符号的情况。

为什么会出现需要在c文件中直接dlopen动态库的情况呢? 这种情况一般出现在又不想重启进行,又需要有功能更新的情况。比如nginx服务器,在不重启web服务器的,需要增加一个filter模块,filter模块肯定是需要访问nginx内部函数和变量的,这种情况下,问题就引出来了。

如何共享变量呢?linux是通过什么机制来共享呢?我们通过一个例子来说明看看。

hello.c 用来编译成libhello.so

void hello()
{
        share_fun();
}

main.c主函数

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

void share_fun()
{
        printf("aa\n");
}

main()
{
        void *ptr = NULL;
        void (*hello)(void);

        ptr = dlopen("/home/mywork/libhello.so", RTLD_LAZY);
        if (ptr == NULL) {
                printf("error dlopen\n");
                return -1;
        }

        hello = dlsym(ptr, "hello");
        if (hello == NULL) {
                printf("error get fun\n");
                return -1;
        }

        hello();
        return 0;
}

两个文件中我们可以看到,共享库libhello.so中访问了share_fun函数,而这个函数是定义在主文件中的。

我们通过以下命令讲hello.c编译成libhello.so

gcc -fPIC -shared libhello.so hello.c

通过以下命令生成main可执行文件。

gcc main.c -o main -ldl

执行结果

./main: symbol lookup error: /home/mywork/libhello.so: undefined symbol: share_fun

通过以下命令生成main可执行文件。

gcc main.c -o main -ldl -L./ -lhello

执行结果

aa

为什么会出现这种情况呢?先看看linux中动态库是如何访问未定义符号的,以下是libhello.so中share_fun在elf文件中的位置:

Relocation section ‘.rel.plt‘ at offset 0x374 contains 3 entries:

Offset     Info    Type            Sym.Value  Sym. Name

0000200c  00000207 R_386_JUMP_SLOT   00000000   share_fun

00002010  00000307 R_386_JUMP_SLOT   00000000   __cxa_finalize

00002014  00000407 R_386_JUMP_SLOT   00000000   __gmon_start__

The decoding of unwind sections for machine type Intel 80386 is not currently supported.

Symbol table ‘.dynsym‘ contains 13 entries:

Num:    Value  Size Type    Bind   Vis      Ndx Name

0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND

1: 00000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_deregisterTMCloneTab

2: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND share_fun

3: 00000000     0 FUNC    WEAK   DEFAULT  UND [email protected]_2.1.3 (2)

4: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__

5: 00000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses

从上面可以看出share_fun因为在动态库中没有定义,从而被安置在了重定向段中,也就是说在编译时无法确定函数的准确地址,需要在运行加载时才能确定。

并且我们还可以看到share_fun被定为动态符号。

第一种情况下,main中动态符号并没有share_fun

[[email protected] mywork]# gcc main.c -o main -ldl

[[email protected] mywork]# ./main

./main: symbol lookup error: /home/mywork/libhello.so: undefined symbol: share_fun

[[email protected] mywork]# nm -D main

0804867c R _IO_stdin_used

w _ITM_deregisterTMCloneTable

w _ITM_registerTMCloneTable

w _Jv_RegisterClasses

w __gmon_start__

U __libc_start_main

U dlopen

U dlsym

U puts

第二种情况下,main中动态符号表里面含有share_fun

[[email protected] mywork]# gcc main.c -o main -ldl -L./ -lhello

[[email protected] mywork]# ./main

aa

[[email protected] mywork]# nm -D main

0804873c R _IO_stdin_used

w _ITM_deregisterTMCloneTable

w _ITM_registerTMCloneTable

w _Jv_RegisterClasses

0804a024 B __bss_start

w __gmon_start__

U __libc_start_main

0804a024 D _edata

0804a028 B _end

08048724 T _fini

0804847c T _init

U dlopen

U dlsym

U puts

08048610 T share_fun

从上可以看到动态库中访问主程序的函数时,符号的共享是通过动态段来实现的,当没有动态段时,是无法实现共享的,函数和变量都是一样。

从原理上讲,动态库或者主程序中没有定义的函数,都会在重定向表中,需要在程序中加载阶段进行动态映射,所以主程序和动态库共享和静态编译是相冲突的。

知道了原理,要解决办法就容易了,以下编译选项都能将符号导出到动态段,从而实现主程序和动态库符号访问。

-Bsymbolic

When creating a shared library, bind references to global symbols to the definition within the shared library, if any.  Normally, it is possible for a

program linked against a shared library to override the definition within the shared library.  This option is only meaningful on ELF platforms which

support shared libraries.

-Bsymbolic-functions

When creating a shared library, bind references to global function symbols to the definition within the shared library, if any.  This option is only

meaningful on ELF platforms which support shared libraries.

--dynamic-list=dynamic-list-file

Specify the name of a dynamic list file to the linker.  This is typically used when creating shared libraries to specify a list of global symbols whose

references shouldn‘t be bound to the definition within the shared library, or creating dynamically linked executables to specify a list of symbols which

should be added to the symbol table in the executable.  This option is only meaningful on ELF platforms which support shared libraries.

The format of the dynamic list is the same as the version node without scope and node name.  See VERSION for more information.

--dynamic-list-data

Include all global data symbols to the dynamic list.

时间: 2024-10-06 10:52:06

linux主文件和动态库之间变量和函数访问的相关文章

Linux系统中“动态库”和“静态库”那点事儿 /etc/ld.so.conf 动态库的后缀为*.so 静态库的后缀为 libxxx.a ldconfig 目录名

Linux系统中“动态库”和“静态库”那点事儿 /etc/ld.so.conf  动态库的后缀为*.so  静态库的后缀为 libxxx.a   ldconfig   目录名 转载自:http://blog.chinaunix.net/uid-23069658-id-3142046.html 今天我们主要来说说Linux系统下基于动态库(.so)和静态(.a)的程序那些猫腻.在这之前,我们需要了解一下源代码到可执行程序之间到底发生了什么神奇而美妙的事情. 在Linux操作系统中,普遍使用ELF格

Linux下的动态库与静态库

2019-09-25 关键字:生成库.静态库引用.动态库引用 在 C 开发中,“库”是一个经常听到的名词. 所谓的库其实就是一个二进制文件.这个二进制文件的内容是可被其它C程序调用执行的函数.换句话说,库就是一组C代码的打包形式而已,打包是指将源代码以库的形式编译而生成的文件. 不过即使它只是源代码的打包,它也仍然是有系统专有性的,即不同系统下编译出来的库并不能互相兼容使用. C库可分为动态库与静态库两种.引用了外部库的应用程序在编译时会在”链接期“处理库与程序源码之间的关系. 1.静态库 静态

用Vs2013+VELT进行Linux开发:动态库

快乐虾 http://blog.csdn.net/lights_joy/ 欢迎转载,但请保留作者信息 本文适用于vs2013 + Visual EmbedLinux Tools 0.1.1 1.1    什么是VELT VELT的全称是Visual EmbedLinuxTools,它是一个与visual gdb类似的visual studio插件,用以辅助完成Linux开发.利用这个插件,将可以在visual studio的IDE中进行Linux应用程序的开发(包括编译和调试),也可以进行ubo

【转】分析Linux和windows动态库

原文地址:http://www.cnblogs.com/chio/archive/2008/11/13/1333119.html 摘要:动态链接库技术实现和设计程序常用的技术,在Windows和Linux系 统中都有动态库的概念,采用动态库可以有效的减少程序大小,节省空间,提高效率,增加程序的可扩展性,便于模块化管理.但不同操作系统的动态库由 于格式不同,在需要不同操作系统调用时需要进行动态库程序移植.本文分析和比较了两种操作系统动态库技术,并给出了将Visual C++编制的动态库移植到Lin

用VS2013+VELT-0.1.3进行Linux开发:动态库

快乐虾 http://blog.csdn.net/lights_joy/(QQ群:Visual EmbedLinux Tools 375515651) 欢迎转载,但请保留作者信息 本文仅适用于vs2013 + velt-0.1.3 1.1    什么是VELT VELT的全称是Visual EmbedLinuxTools,它是一个与visual gdb类似的visual studio插件,用以辅助完成Linux开发.利用这个插件,将可以在visual studio的IDE中进行Linux应用程序

linux下so动态库一些不为人知的秘密

linux 下有动态库和静态库,动态库以.so为扩展名,静态库以.a为扩展名.二者都使用广泛.本文主要讲动态库方面知识.    基本上每一个linux 程序都至少会有一个动态库,查看某个程序使用了那些动态库,使用ldd命令查看 # ldd /bin/ls linux-vdso.so.1 => (0x00007fff597ff000) libselinux.so.1 => /lib64/libselinux.so.1 (0x00000036c2e00000) librt.so.1 => /

Linux和windows动态库

转载:http://www.cnblogs.com/chio/archive/2008/11/13/1333119.html 态链接库技术实现和设计程序常用的技术,在Windows和Linux系 统中都有动态库的概念,采用动态库可以有效的减少程序大小,节省空间,提高效率,增加程序的可扩展性,便于模块化管理.但不同操作系统的动态库由 于格式不同,在需要不同操作系统调用时需要进行动态库程序移植.本文分析和比较了两种操作系统动态库技术,并给出了将Visual C++编制的动态库移植到Linux上的方法

linux下so动态库一些不为人知的秘密(转)

linux 下有动态库和静态库,动态库以.so为扩展名,静态库以.a为扩展名.二者都使用广泛.本文主要讲动态库方面知识.基本上每一个linux 程序都至少会有一个动态库,查看某个程序使用了那些动态库,使用ldd命令查看 # ldd /bin/ls 使用 ldd -u /bin/ls 查看不需要链接的so 大家知不知道linux从程序(program或对象)变成进程(process或进程),要经过哪些步骤呢,这里如果详细的说,估计要另开一篇文章.简单的说分三步:    1.fork进程,在内核创建

运行时库以及静态库,动态库之间的关系

了解篇 http://www.cnblogs.com/renyuan/p/5031100.html 知道MT,MD之间的不同,MT会将LIBC.LIB或者LIBCMT.LIB打包进可执行程序, 而MD则告诉可执行程序,运行的时候调用msvcrt.dll,因此任何一个工程 只能选择运行时库中的一种方式,MD,MDd,MT,MTd,这四种方式的一种, 连接C库,不管是一个静态库,还是一个动态库,还是一个可执行程序, 链接的其他库的时候,都必须保持一致,否则就会出现如下的提示: 错误 LNK2038