Linux动态库与静态库同名函数链接顺序问题

1. 调用过程

main(主程序) --> calltest()函数 (libcalltest.so) --> funtest()函数

funtest()函数有两个地方实现,动态库是weak类型的实现,静态库是默认类型。期望是可以屏蔽掉动态库里的实现,调用到静态库中,但实际调用和链接顺序有关。

  • 动态库:libfuntest.so (weak类型
[func]$ nm -D libfuntest.so 
0000000000000685 W funtest
  • 静态库:
[func]$ nm -A libstfunctest.a 
libstfunctest.a:stfunctest.o:0000000000000000 T funtest

2. 代码实现

  1. main.c
#include <stdio.h>
#include <stdlib.h>

extern void calltest();
int main(void)
{
        calltest();
        return 0;
}
  1. calltest.c
#include <stdlib.h>
#include <stdio.h>

extern void funtest();
void calltest (void)
{
        printf("This is calltest, call funtest\n");
        funtest();
}

编译libcalltest.so

gcc -fPIC -c calltest.c -o libcalltest.o
gcc -shared -o libcalltest.so libcalltest.o
或
gcc -fPIC -shared calltest.c -o libcalltest.so
  1. stfunctest.c
#include <stdlib.h>
#include <stdio.h>

void funtest (void)
{
        printf("This is a funtest\n");
}

编译libstfunctest.a

gcc -c stfunctest.c -o stfunctest.o
ar rc libstfunctest.a stfunctest.o
  1. funtest.c
#include <stdlib.h>
#include <stdio.h>

#define weak_alias(name, aliasname) _weak_alias (name, aliasname)
#define _weak_alias(name, aliasname) \
  extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)));

void __funtest (void)
{
        printf("This is so funtest\n");
}
weak_alias (__funtest, funtest)

编译libcalltest.so

gcc -fPIC -c funtest.c -o libfuntest.o
gcc -shared -o libfuntest.so libfuntest.o

3. 链接验证

动态库路径:

export LD_LIBRARY_PATH=/home/test/func:$LD_LIBRARY_PATH
  1. 仅有这个顺序调用静态库中函数:-lcalltest -lstfunctest -lfuntest
[func]$ gcc main.c -L. -lcalltest -lstfunctest -lfuntest
[func]$ ./a.out 
This is calltest, call funtest
This is a funtest
  1. 其余情况都调用的so中的weak函数
[func]$ gcc main.c -L. -lfuntest -lstfunctest -lcalltest
[func]$ ./a.out 
This is calltest, call funtest
This is so funtest
[func]$ gcc main.c -L. -lstfunctest -lfuntest -lcalltest
[func]$ ./a.out 
This is calltest, call funtest
This is so funtest
[func]$ gcc main.c -L. -lstfunctest -lcalltest -lfuntest
[func]$ ./a.out 
This is calltest, call funtest
This is so funtest
[func]$ gcc main.c -L. -lcalltest -lfuntest -lstfunctest
[func]$ ./a.out 
This is calltest, call funtest
This is so funtest
[func]$ gcc main.c -L. -lfuntest -lcalltest -lstfunctest
[func]$ ./a.out 
This is calltest, call funtest
This is so funtest

4. 原因总结

默认情况下,对于未使用到的符号,链接器不会将它们链接进共享库和可执行程序,也就是默认参数为-Wl,-no-whole-archive
综上,想要静态库-lstfunctest被链接进去,第一个链接的库必须是调用库-lcalltest,链接器才知道有对应的符号需要被链接。其次静态库-lstfunctest必须在动态库-lfuntest之前;否则先链接的动态库中符号,之后因为已链接符号则不会再把静态库链接进来。
也可以改成将静态库符号全部链进来:

gcc main.c -L. -Wl,--whole-archive -lstfunctest -Wl,--no-whole-archive -lcalltest -lfuntest
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值