个人创作,欢迎指错。
牵扯到ELF格式,gcc编译选项待补,简单实用的说明一下,对Linux下的so文件有个实际性的认识。
1.so文件是什么?
2.怎么生成以及使用一个so动态库文件?
3.地址空间,以及线程安全.
4.库的初始化,解析:
5.使用我们自己库里的函数替换系统函数:
//-------------------------------------------------------------------------------
1.so文件是什么?
也是ELF格式文件,共享库(动态库),类似于DLL。节约资源,加快速度,代码升级简化。
知道这么多就够了,实用主义。等有了印象再研究原理。
2.怎么生成以及使用一个so动态库文件?
先写一个C文件:s.c
#include <stdio.h>
int count;
void out_msg(const char *m)
{//2秒钟输出1次信息,并计数
for(;;) {printf("%s %d\n", m, ++count); sleep(2);}
}
编译:得到输出文件libs.o
gcc -fPIC -g -c s.c -o libs.o
链接:得到输出文件libs.so
gcc -g -shared -Wl,-soname,libs.so -o libs.so libs.o -lc
一个头文件:s.h
#ifndef _MY_SO_HEADER_
#define _MY_SO_HEADER_
void out_msg(const char *m);
#endif
再来一个C文件来引用这个库中的函数:ts.c
#include <stdio.h>
#include "s.h"
int main(int argc, char** argv)
{
printf("TS Main\n");
out_msg("TS ");
sleep(5); //这句话可以注释掉,在第4节的时候打开就可以。
printf("TS Quit\n");
}
编译链接这个文件:得到输出文件ts
gcc -g ts.c -o ts -L. -ls
执行./ts,嗯:成功了。。。还差点
得到了ts:error while loading shared libraries: libs.so: cannot open shared object file: No such file or directory
系统不能找到我们自己定义的libs.so,那么告诉他,修改变量LD_LIBRARY_PATH,为了方便,写个脚本:e(文件名就叫e,懒得弄长了)
#!/bin/sh
export LD_LIBRARY_PATH=${pwd}:${LD_LIBRARY_PATH}
./ts
执行:./e &
屏幕上就开始不停有信息输出了,当然TS Quit你是看不到的,前面是个死循环,后面会用到这句
3.地址空间,以及线程安全:
如果这样:
./e &开始执行后,稍微等待一下然后再 ./e&,
这个时候屏幕信息会怎么样呢?全局变量count会怎么变化?
会是两个进程交叉输出信息,并且各自的count互不干扰,虽然他们引用了同一个so文件。
也就是说只有代码是否线程安全一说,没有代码是否是进程安全这一说法。
4.库的初始化,解析:
windows下的动态库加载,卸载都会有初始化函数以及卸载函数来完成库的初始化以及资源回收,linux当然也可以实现。
ELF文件本身执行时就会执行一个_init()函数以及_fini()函数来完成这个,我们只要把自己的函数能让系统在这个时候执行
就可以了。
修改我们前面的s.c文件:
#include <stdio.h>
void my_init(void) __attribute__((constructor)); //告诉gcc把这个函数扔到init section
void my_fini(void) __attribute__((destructor)); //告诉gcc把这个函数扔到fini section
void out_msg(const char *m)
{
printf(" Ok!\n");
}
int i; //仍然是个计数器
void my_init(void)
{
printf("Init ... ... %d\n", ++i);
}
void my_fini(void)
{
printf("Fini ... ... %d\n", ++i);
}
重新制作 libs.so,ts本是不用重新编译了,代码维护升级方便很多。
然后执行: ./e &
可以看到屏幕输出:(不完整信息,只是顺序一样)
Init
Main
OK
Quit
Fini
可以看到我们自己定义的初始化函数以及解析函数都被执行了,而且是在最前面以及最后面。
如果s.c中的sleep(5)没有注释掉,那么有机会:
./e&
./e&连续执行两次,那么初始化函数和解析函数也会执行两次,虽然系统只加载了一次libs.so。
如果sleep时候kill 掉后台进程,那么解析函数不会被执行。
5.使用我们自己库里的函数替换系统函数:
创建一个新的文件b.c:我们要替换系统函数malloc以及free(可以自己写个内存泄露检测工具了)
#include <stdio.h>
void* malloc(int size)
{
printf("My malloc\n");
return NULL;
}
void free(void* ad)
{
printf("My free\n");
}
老规矩,编译链接成一个so文件:得到libb.so
gcc -fPIC -g -c b.c -o libb.o
gcc -g -shared -Wl,-soname,libb.so -o libb.so -lc
修改s.c:重新生成libs.so
void out_msg()
{
int *p;
p = (int*)malloc(100);
free(p);
printf("Stop Ok!\n");
}
修改脚本文件e:
#!/bin/sh
export LD_PRELOAD=${pwd}libb.so:${LD_PRELOAD}
export LD_LIBRARY_PATH=${pwd}:${LD_LIBRARY_PATH}
./ts
关键就在LD_PRELOAD上了,这个路径指定的so将在所有的so之前加载,并且符号会覆盖后面加载的so文件中的符号。如果可执行文件的权限不合适(SID),这个变量会被忽略。
执行:./e &
嗯,可以看到我们的malloc,free工作了。
暂时就想到这么多了。
分享到:
相关推荐
linux调用动态库so文件整理.pdf
LINUX动态库.so嵌套.so文件,二次封装,完整源码,演示项目齐全
Linux x64 Opencv 3.4.3所有动态库so文件,包含 jar,windows下所需的dll,以及所有相关的so文件
linux调用动态库so文件[汇编].pdf
linux下编译.so库文件
我的工作最近需要用到linux下构建多目录下Makefile产生so动态库样例的知识,我将最新的学习心得,做一个记录分享,以便以后需要使用时可以做参考。
默认编译是静态库,但考虑到 linux 上动态库使用较多,所以使用 -DBUILD_SHARED_LIBS=ON 参数编译为动态库。 在 centos 7 下使用 gcc 4.8.5 + cmake 3.16.9 编译,包含 bin, include, lib, lib64, share 五个目录,...
linux静态库和动态库的区别
Linux下动态库研究及应用pdf文件描述了动态库生成的方法 并给出了实例
Linux动态链接库.so文件的创建与使用
linux动态库生成,linux动态库生成,linux动态库生成,linux动态库生成,linux动态库生成
linux系统下用eclipse开发c++动态库(MyDll),并用c++程序(HelloWord)静态和动态2种方法调用动态库的例子,里面有比较详细的注释,适合初学者。
kafka C++ linux 编译后的动态库文件,含.h和so文件,编译环境:g++4.x, centos.
Linux下动态库研究及应用.pdf
这是个LINUX下生成SO文件,和调用SO库的程序示例.
Ubuntu linux动态库静态库的创建与使用附工程代码....
Linux下动态库文件的扩展名为\".so\"(Shared Object)。按照约定,所有动态库文件名的形式是libname.so(可能在名字中加入版本号)。这样,线程函数库被称作libthread.so。静态库的文件名形式是libname.a。共享...
描述linux下动态库的建立和使用,有具体例子示范,很好的学习资料。
Android编程过程中,在Linux 环境中编译C、C++文件生成.so文件
QT5.7.0 Linux版本动态库开发文件,适合链接动态库的项目