深析静态链接库和动态链接库相同函数覆盖及库调用顺序问题
2016-12-21 10:47
459 查看
注意:编译器为gcc,若使用g++,请在库里面加上extern “C”
两个静态库
首先测试静态链接库,大概的代码如下:
liba.c
#include <stdio.h>
#include <stdlib.h>
#include "libA.h"
void libA()
{
common();
}
void common()
{
printf("libA common!\n");
}
liba.h
#ifndef __LIBA_H__
#define __LIBA_H__
void libA();
void common();
#endif
libb.c
#include <stdio.h>
#include <stdlib.h>
#include "libB.h"
void libB()
{
common();
}
void common()
{
printf("libB common!\n");
}
libb.h
#ifndef __LIBB_H__
#define __LIBB_H__
void libB();
void common();
#endif
静态库的生成:
gcc -c liba.c
ar -rs liba.a liba.o
gcc -c libb.c
ar -rs libb.a libb.o
动态库生成:
gcc -fpic -shared -o liba.so liba.c
gcc -fpic -shared -o libb.so libb.c
fpic:表示为位置无关,也即在任何内存位置都可以运行。
可以看到liba和libb都有相同的common函数,但是打印出的内容都是自家的。
下面我们分别生成静态链接库做测试,生成好后,写个主程序进行测试。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
int main()
{
libA();
libB();
return 0;
}
编译生成结果如下:
可以得出一个结论:都为静态链接库,有同名函数参与的情况下,链接会出现符号多次定义的错误。
两个动态库
再来看看动态链接库,同样的liba、libb生成动态链接库
测试主程序不修改,还是为:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
int main()
{
liba();
libb();
return 0;
}
编译结果和顺序,结果如下:
这种编译方式叫做动态链接库的隐式调用,如果你删除一个liba.so,运行a.out会出现不能找到动态库的错误。
这种情况也可以称为 加载时链接!静态库属于编译时链接!
可以得出第二个结论:若都为动态库,并且进行隐式调用,输出结果和动态库的顺序有关。
再继续看看动态加载动态库。
修改测试程序
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
int main()
{
void* handle2 = NULL;
void (*testLibA)();
handle2 = dlopen("./libA.so", RTLD_LAZY);
if (handle2 == NULL) {
perror("error!");
return ;
}
testLibA = dlsym(handle2, "libA");
if (testLibA == NULL) {
perror("error!");
return ;
}
void* handle = NULL;
void (*testLibB)();
handle = dlopen("./libB.so", RTLD_LAZY);
if (handle == NULL) {
perror("error!");
return ;
}
testLibB = dlsym(handle, "libB");
if (testLibB == NULL) {
perror("error!");
return ;
}
testLibA();
testLibB();
return 0;
}
编译结果如下所示:
这种情况称为运行时链接。
如果我们再把动态库的名字加上去呢?
同样可以得出结论:动态链接库如果不加库选项,函数调用是正确的,加库路径,会以库的路径顺序为主!左边覆盖右边。而且当只链接一个时也生效。如:
一个静态,一个动态
再来看看一个静态文件和一个动态文件。
修改测试主程序
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
int main()
{
void* handle2 = NULL;
void (*testLibA)();
handle2 = dlopen("./libA.so", RTLD_LAZY);
if (handle2 == NULL) {
perror("error!");
return ;
}
testLibA = dlsym(handle2, "libA");
if (testLibA == NULL) {
perror("error!");
return ;
}
testLibA();
libB();
return 0;
}
测试结果如下:
libb为静态链接!liba为动态加载。
输出正常!
再看下如果动态库的库名显示的加载如编译选项中:
结论:在有静态库和动态库时,不把动态库名显示加入编译选项,输出是正常的,如果加进去以静态库为主,和link的顺序无关。
补充:
另外:
这种一个共享对象里面的全局符号被另一个共享对象的全局符号覆盖的现象又被称为共享对象的全局符号介入。
关于全局符号介入这个问题,实际上Linux下的动态链接器是这样处理的:它定义了一个规则,那就是当一个符合需要被加入到全局符号表时,如果相同的符号名已经存在,则后加入的忽略。从动态链接器的角度的装载顺序可以看到,它是按广度优先的顺序进行装载的。
原文地址:http://blog.chinaunix.net/uid-26548237-id-3837099.html
两个静态库
首先测试静态链接库,大概的代码如下:
liba.c
#include <stdio.h>
#include <stdlib.h>
#include "libA.h"
void libA()
{
common();
}
void common()
{
printf("libA common!\n");
}
liba.h
#ifndef __LIBA_H__
#define __LIBA_H__
void libA();
void common();
#endif
libb.c
#include <stdio.h>
#include <stdlib.h>
#include "libB.h"
void libB()
{
common();
}
void common()
{
printf("libB common!\n");
}
libb.h
#ifndef __LIBB_H__
#define __LIBB_H__
void libB();
void common();
#endif
静态库的生成:
gcc -c liba.c
ar -rs liba.a liba.o
gcc -c libb.c
ar -rs libb.a libb.o
动态库生成:
gcc -fpic -shared -o liba.so liba.c
gcc -fpic -shared -o libb.so libb.c
fpic:表示为位置无关,也即在任何内存位置都可以运行。
可以看到liba和libb都有相同的common函数,但是打印出的内容都是自家的。
下面我们分别生成静态链接库做测试,生成好后,写个主程序进行测试。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
int main()
{
libA();
libB();
return 0;
}
编译生成结果如下:
可以得出一个结论:都为静态链接库,有同名函数参与的情况下,链接会出现符号多次定义的错误。
两个动态库
再来看看动态链接库,同样的liba、libb生成动态链接库
测试主程序不修改,还是为:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
int main()
{
liba();
libb();
return 0;
}
编译结果和顺序,结果如下:
这种编译方式叫做动态链接库的隐式调用,如果你删除一个liba.so,运行a.out会出现不能找到动态库的错误。
这种情况也可以称为 加载时链接!静态库属于编译时链接!
可以得出第二个结论:若都为动态库,并且进行隐式调用,输出结果和动态库的顺序有关。
再继续看看动态加载动态库。
修改测试程序
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
int main()
{
void* handle2 = NULL;
void (*testLibA)();
handle2 = dlopen("./libA.so", RTLD_LAZY);
if (handle2 == NULL) {
perror("error!");
return ;
}
testLibA = dlsym(handle2, "libA");
if (testLibA == NULL) {
perror("error!");
return ;
}
void* handle = NULL;
void (*testLibB)();
handle = dlopen("./libB.so", RTLD_LAZY);
if (handle == NULL) {
perror("error!");
return ;
}
testLibB = dlsym(handle, "libB");
if (testLibB == NULL) {
perror("error!");
return ;
}
testLibA();
testLibB();
return 0;
}
编译结果如下所示:
这种情况称为运行时链接。
如果我们再把动态库的名字加上去呢?
同样可以得出结论:动态链接库如果不加库选项,函数调用是正确的,加库路径,会以库的路径顺序为主!左边覆盖右边。而且当只链接一个时也生效。如:
一个静态,一个动态
再来看看一个静态文件和一个动态文件。
修改测试主程序
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
int main()
{
void* handle2 = NULL;
void (*testLibA)();
handle2 = dlopen("./libA.so", RTLD_LAZY);
if (handle2 == NULL) {
perror("error!");
return ;
}
testLibA = dlsym(handle2, "libA");
if (testLibA == NULL) {
perror("error!");
return ;
}
testLibA();
libB();
return 0;
}
测试结果如下:
libb为静态链接!liba为动态加载。
输出正常!
再看下如果动态库的库名显示的加载如编译选项中:
结论:在有静态库和动态库时,不把动态库名显示加入编译选项,输出是正常的,如果加进去以静态库为主,和link的顺序无关。
补充:
另外:
这种一个共享对象里面的全局符号被另一个共享对象的全局符号覆盖的现象又被称为共享对象的全局符号介入。
关于全局符号介入这个问题,实际上Linux下的动态链接器是这样处理的:它定义了一个规则,那就是当一个符合需要被加入到全局符号表时,如果相同的符号名已经存在,则后加入的忽略。从动态链接器的角度的装载顺序可以看到,它是按广度优先的顺序进行装载的。
原文地址:http://blog.chinaunix.net/uid-26548237-id-3837099.html
相关文章推荐
- 深析静态链接库和动态链接库相同函数覆盖及库调用顺序问题
- 深析静态链接库和动态链接库相同函数覆盖及库调用顺序问题
- 深析静态链接库和动态链接库相同函数覆盖及库调用顺序问题
- 深析静态链接库和动态链接库相同函数覆盖及库调用顺序问题
- 深析静态链接库和动态链接库相同函数覆盖及库调用顺序问题
- 深析静态链接库和动态链接库相同函数覆盖及库调用顺序问题
- 深析静态链接库和动态链接库相同函数覆盖及库调用顺序问题
- 静态链接库和动态链接库相同函数覆盖及库调用顺序
- 深析静态链接库和动态链接库相同函数覆盖及库调用顺序问题
- 函数调用时参数压栈顺序的问题(转)
- 函数调用顺序的问题
- extern "c" 动态链接库符号表导出问题 以及函数参数压栈顺序
- JavaScript关于自调用循环函数解决代码加载顺序的问题
- 动态加载DLL实现不同DLL的相同导出函数调用问题
- 多个dll导出相同函数时的调用问题
- extern "c" 动态链接库符号表导出问题 以及函数参数压栈顺序
- C# 调用 C++ dll 动态链接库中多个函数时全局变量的问题
- Qt按ESC关闭模态对话框不触发closeEvent()问题解析(ESC默认调用的是reject()函数,所以必须覆盖这个函数才会有效果)good
- C语言学习4: 函数返回值与传入参数,关于函数值传递和类型隐性转换,变量不同的作用域,static变量,多文件编译例如两个C文件,显示函数调用语句跳转,递归,斐波那契数列,多文件编译相同变量的问题。
- 编程经验点滴(二)——《C、C++中函数调用时参数压栈的顺序问题》