个人创作,欢迎指错。
牵扯到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文件的基本信息: 1. `readelf -h <so_file>`:查看.so文件的头部信息,包括文件类型、机器架构、版本、入口点等。 2. `objdump -d <so_file>`:反汇编.so文件中的代码,...
5. **运行时问题**:在Windows上,如果动态库不在系统的PATH环境变量中,需要确保在运行应用程序时动态库文件位于同一目录下,或者将库的路径添加到PATH中。对于Linux和macOS,系统会自动搜索特定路径下的库。 除了...
在深入探索Linux平台下的GCC编译器与动态共享库的基础知识之前,我们首先要理解GCC(GNU Compiler Collection)不仅是一个编译器,更是一套工具集,用于编译多种编程语言,包括C、C++、Fortran等。而动态共享库...
了解了以上流程之后,我们会对Android系统加载so文件的细节有了比较清晰的认识。而这篇文章的作者建议读者在阅读之前需要了解ELF文件格式。ELF,即Executable and Linkable Format,是一种常见的二进制文件格式,...
首先,libmwins.so是一个Linux系统下的动态链接库,其后缀.so是"shared object"的缩写,表明这是一个可以被多个进程共享的代码库。在MATLAB中,这样的库文件主要负责提供特定的功能支持,比如图形用户界面(GUI)的...
- **.so**:Shared Object,表示共享库文件。 - **.o**:Object File,表示编译后的对象文件。 #### 四、包管理工具 - **RPM**:Redhat Package Manager,Red Hat发行版中的包管理工具。 - **dpkg**:Debian ...
对于动态版本的编译,可以通过运行`makeshared`替代`make`,这将生成动态链接库`./lib/libdxf.so.2.0.x.x`以及指向其的符号链接`./lib/libdxf.so`。 安装过程也可以通过手动拷贝头文件到自选的头文件目录,以及将库...
2. **linux-hsdis-amd64.so** 和 **linux-hsdis-i386.so**:这些是针对Linux系统的共享对象文件,同样对应64位AMD和32位Intel处理器。它们使得开发者能够在Linux环境下进行汇编代码的解析。 hsdis的工作原理是通过...
- 结合JNI(Java Native Interface)技术,在Linux环境下编写C/C++代码,并将其作为动态链接库(.so文件)供Android应用程序调用。 #### 五、JNI机制 JNI是Java Native Interface的缩写,用于实现Java代码与其他...
而rxtxSerial.dll是RXTX在Windows环境下运行所需的动态链接库(DLL)文件,它实现了RXTXcomm.jar中定义的接口,使Java代码能够调用底层操作系统提供的串口服务。在非Windows系统中,会有相应的库文件,如在Linux中是...
加载器还可能处理动态链接,确保程序运行时可以访问所需的动态库函数。 在现代操作系统中,加载和连接往往是同时进行的。例如,在Linux系统中,这个过程由ld-linux.so处理,它作为程序的初始部分加载到内存中,负责...
在这个So-lab-5实验中,我们将深入探讨操作系统的一些基本概念,尤其是与文件管理和目录结构相关的部分。我们将使用C语言来实现一些基本的操作,如创建目录。 在计算机系统中,目录结构是一个重要的组织方式,它...
此文件可能深入讨论了Android应用的编译过程、.so库的处理、NDK开发等相关技术,对于进行原生代码开发的开发者特别有用。 这些资源为Android开发者提供了广泛而深入的知识,无论是对Android系统的基本操作,还是对...
UG NX插件通常被打包为DLL动态链接库文件(Windows平台)或者.so共享对象文件(Unix/Linux平台),然后通过UG NX的加载机制进行安装。在部署过程中,需要确保插件与UG NX软件的版本兼容,并且遵循NX Open的插件部署...