linux 动态库构造函数,Linux共享库全局构造函数的相互依赖性

操作系统Centos 5.6 i686 2.6.18-53.1.4.el5vm.

gcc版本4.1.2 20080704(Red Hat 4.1.2-48)

ld版本2.17.50.0.6-6.el5 20061020

我以这种方式编译:

gcc -c -fnon-call-exceptions -fexceptions -Wall -DUNICODE -D_UNICODE -D_REENTRANT -I.

并以这种方式链接:

gcc -lstdc -pthread -ldl -lrt –no-relocate -Wl,-rpath,$SO_DIR -L $SO_DIR $LIBRARIES

我有3个库和一个可执行文件:A.so,B.so,C.so,ElfExec

B.so取决于A.so.

C.so取决于B.so.

在代码A.so中具有通过其公开功能A.h的标头,在代码中B.so具有B.h标头,其中包括A.h和B的功能.代码中的C.so包括B.h.

A.h定义了一个静态变量K,该类型可以在且仅当初始化A.so的静态内存管理器时使用.变量K在头文件A.h中直接定义,因此,它的初始化在组成B.so和C.so的所有对象的全局构造函数中传播.

我像这样链接所有内容:

gcc“所有B模块” -lstdc -pthread -ldl -lrt –no-relocate -Wl,-rpath,$SO_DIR -L $SO_DIR A.so

gcc“所有C模块” -lstdc -pthread -ldl -lrt-无重定位-Wl,-rpath,$SO_DIR -L $SO_DIR B.so

gcc“所有ElfExec模块” -lstdc -pthread -ldl -lrt –no-relocate -Wl,-rpath,$SO_DIR -L $SO_DIR C.so

我也尝试过:

gcc“所有ElfExec模块” -lstdc -pthread -ldl -lrt –no-relocate -Wl,-rpath,$SO_DIR -L $SO_DIR A.so B.so C.so

ElfExec在运行时会收到SIGSEGV,因为它会在初始化A.so的静态内存管理器之前尝试初始化变量K.

这是因为C.so的全局构造函数在A.so的全局构造函数之前被调用.

如果我制作只需要B.so的应用程序ElfExec2

gcc“所有ElfExec1模块” -lstdc -pthread -ldl -lrt –no-relocate -Wl,-rpath,$SO_DIR -L $SO_DIR B.so

这正常工作.

对于ElfExec1,链接器看到需要先调用A.so中的全局构造函数,然后再调用B.so中的全局构造函数.

在ElfExec的情况下,这不会受到限制.

我的解决方案是这样链接C.so:

gcc“所有C模块” -lstdc -pthread -ldl -lrt –no-relocate -Wl,-rpath,$SO_DIR -L $SO_DIR A.so B.so

这使C.so与A.so直接相关.

还有另一种方式可以告诉链接程序全局构造函数调用的顺序吗?

解决方法:

如您所见,不要相信链接器比您更了解.如果顺序很重要,则需要以编程方式指定顺序.不要只是试图欺骗链接器.

如果这些不是库,那就是您要做的,对吧?以正确的顺序互相调用的构造函数/初始化函数?

我的第一选择是将库设计为不具有或使用全局变量.

如果您不能这样做,那么我的第二个选择是为每个需要初始化全局变量以具有init方法的库.库的使用者需要先调用该init方法,然后才能执行任何操作,并且库必须尝试阻止使用/构造,直到正确完成init为止.也许将它们静态化为init方法,然后设置指向它们的全局指针(K * k)可能有助于实现.这应该足以使初始化链以正确的顺序组合在一起.

最后,如果让任何库的用户(对于A表示B,对于C表示B,对于C而言,C)的用户都遇到障碍,则可以对gcc使用如下语言扩展:

extern "C" __attribute__ ((constructor)) void A_lib_ctor()

{

// ....

}

extern "C" __attribute__ ((destructor)) void A_lib_dtor()

{

// ....

}

在加载库时自动执行所需的操作.这牺牲了一些可移植性.可能会牺牲更多,较新版本的gcc支持构造函数(优先级)语法.

我的最后选择是使用dlopen手动加载库的复杂步骤.

对于您而言,最重要的选择是设计更好,而后来的选择则更糟.

标签:gcc,linker,ld,linux

来源: https://codeday.me/bug/20191102/1991358.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux设备驱动程序学习(0)-Hello, world!模块 Linux设备驱动程序学习(0) -Hello, world!模块 一个学习Linux设备驱动程序都会碰到的第一个例程: #include #include MODULE_LICENSE("Dual BSD/GPL"); static int hello_init(void) { printk(KERN_ALERT "Hello, Tekkaman Ninja !\n"); return 0; } static void hello_exit(void) { printk(KERN_ALERT "Goodbye, Tekkaman Ninja !\n Love Linux !Love ARM ! Love KeKe !\n"); } module_init(hello_init); module_exit(hello_exit); 我将其复制到我的工作目录,并编写了一个简单的Makefile文件: KERNELDIR = /home/tekkaman/working/SBC2440/linux-2.6.22.2 # The current directory is passed to sub-makes as argument PWD := $(shell pwd) INSTALLDIR = /home/tekkaman/working/rootfs/lib/modules CROSS_COMPILE =/home/tekkaman/working/crosstool-gcc410-k26222/gcc-4.1.0-glibc-2.3.2/arm-9tdmi-linux-gnu/bin/arm-9tdmi-linux-gnu- CC = $(CROSS_COMPILE)gcc obj-m := hello.o modules: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules modules_install: cp hello.ko $(INSTALLDIR) clean: rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions .PHONY: modules modules_install clean 说实话,以上是我参考了《Linux设备驱动程序(第3版)》的Makefile源码修改得来的。我对Makefile不是很了解,是该好好学习学习了! 然后就是make modules 、 make modules_install 。 [root@Tekkaman-Ninja Helloworld]# make modules make -C /home/tekkaman/working/SBC2440/linux-2.6.22.2 M=/home/tekkaman/working/Linuxdriver/Helloworld modules make[1]: Entering directory `/home/tekkaman/working/SBC2440/linux-2.6.22.2' CC [M] /home/tekkaman/working/Linuxdriver/Helloworld/hello.o Building modules, stage 2. MODPOST 1 modules CC /home/tekkaman/working/Linuxdriver/Helloworld/hello.mod.o LD [M] /home/tekkaman/working/Linuxdriver/Helloworld/hello.ko make[1]: Leaving directory `/home/tekkaman/working/SBC2440/linux-2.6.22.2' [root@Tekkaman-Ninja Helloworld]# make modules_install cp hello.ko /home/tekkaman/working/rootfs/lib/modules [root@Tekkaman-Ninja Helloworld]# 在我的开发板上的操作: [Tekkaman2440@SBC2440V4]#cd /lib/modules/ [Tekkaman2440@SBC2440V4]#ls cs89x0.ko hello.

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值