来源:http://mypyg.iteye.com/blog/845915

so其实就是shared object的意思。今天看了上面的博客,感觉好吃力。赶紧做个笔记记录一下。下面的内容大多都是连接中的,穿插我自己的笔记

牵扯到ELF格式,gcc编译选项待补,简单实用的说明一下,对Linux下的so文件有个实际性的认识。

1.so文件是什么? 
2.怎么生成以及使用一个so动态库文件? 
3.地址空间,以及线程安全. 
4.库的初始化,解析: 
5.使用我们自己库里的函数替换系统函数:

1.so文件是什么? 
也是ELF格式文件,共享库(动态库),类似于DLL。节约资源,加快速度,代码升级简化。 
知道这么多就够了,实用主义。等有了印象再研究原理。

2.怎么生成以及使用一个so动态库文件? 
先写一个C文件:s.c

编译:得到输出文件libs.o 
gcc -fPIC -g -c s.c -o libs.o 

----------------------------------------------------------------------

-fPIC:  -fPIC作用于编译阶段,告诉编译器产生与位置无关代码(Position-Independent Code),则产生的代码中,没有绝对地址,全部使用相对地址,故而代码可以被加载器加载到内存的任意 位置,都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。

-g:  令 gcc 生成调试信息,该选项可以利用操作系统的“原生格式(native format)”生成调试信息。GDB 可以直接利用这个信息,其它调试器也可以使用这个调试信息

-c:  仅执行编译操作,不进行连接操作。
-o:  指定生成的输出文件名称

注意!-c,-o是指.c文件和.o文件!!

----------------------------------------------------------------------
链接:得到输出文件libs.so 
gcc -g -shared -Wl,-soname,libs.so -o libs.so libs.o -lc 

-----------------------------------------------------------------------

上述语句中 libs.o是输入文件

-shared:

  Produce a shared object which can then be linked with other objects to form an executable. Not all systems support this option. For predictable results, you must also specify the same set of options used for compilation (-fpic, -fPIC, or model suboptions) when you specify this linker option.

-Wl: 注意第二个字母是小写的L,不是I 

  Pass option as an option to the linker. If option contains commas, it is split into multiple options at the commas. You can use this syntax to pass an argument to the option. For example, -Wl,-Map,output.map passes -Map output.map to the linker. When using the GNU linker, you can also get the same effect with -Wl,-Map=output.map.

-soname:

  soname的关键功能是它提供了兼容性的标准:

  当要升级系统中的一个库时,并且新库的soname和老库的soname一样,用旧库链接生成的程序使用新库依然能正常运行。这个特性使得在Linux下,升级使得共享库的程序和定位错误变得十分容易。

  在Linux中,应用程序通过使用soname,来指定所希望库的版本,库作者可以通过保留或改变soname来声明,哪些版本是兼容的,这使得程序员摆脱了共享库版本冲突问题的困扰。

-lc:

  -l 是直接加上某库的名称,如-lc是libc库 -L 是库的路径,搜索的时候优先在-L目录下搜索

------------------------------------------------------------------------

一个头文件:s.h

#ifndef _MY_SO_HEADER_
#define _MY_SO_HEADER_
void out_msg(const char *m);
#endif

再来一个C文件来引用这个库中的函数:ts.c

编译链接这个文件:得到输出文件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,懒得弄长了)

export LD_LIBRARY_PATH=${pwd}:${LD_LIBRARY_PATH}
./ts

执行:./e & 
屏幕上就开始不停有信息输出了,当然TS Quit你是看不到的,前面是个死循环,后面会用到这句

----------------------

& 放在启动参数后面表示设置此进程为后台进程。默认情况下,进程是前台进程,这时就把Shell给占据了,我们无法进行其他操作,对于那些没有交互的进程,很多时候,我们希望将其在后台启动,可以在启动参数的时候加一个'&'实现这个目的。

----------------------

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();
free(p);
printf("Stop Ok!\n");
}

修改脚本文件e:

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】linux下动态库so文件的一些认识的更多相关文章

  1. linux下动态库so文件的一些认识

    转自:http://mypyg.iteye.com/blog/845915 个人创作,欢迎指错. 牵扯到ELF格式,gcc编译选项待补,简单实用的说明一下,对Linux下的so文件有个实际性的认识.  ...

  2. Linux下动态库查找路径的问题

    说到和动态库查找路径相关的问题,总体上可以分为两类:    第一类: 通过源代码编译程序时出现的找不到某个依赖包的问题,而如果此时你恰好已经按照它的要求确确实实.千真万确.天地良心地把依赖库给装好了, ...

  3. 谈谈Linux下动态库查找路径的问题 ldconfig LD_LIBRARY_PATH PKG_CONFIG_PATH

    谈谈Linux下动态库查找路径的问题 ldconfig LD_LIBRARY_PATH  PKG_CONFIG_PATH 转载自:http://blog.chinaunix.net/xmlrpc.ph ...

  4. 谈谈Linux下动态库查找路径的问题

    学习到了一个阶段之后,就需要不断的总结.沉淀.清零,然后才能继续"上路".回想起自己当年刚接触Linux时,不管是用源码包编译程序,还是程序运行时出现的和动态库的各种恩恩怨怨,心里 ...

  5. [转]谈谈Linux下动态库查找路径的问题

    http://blog.chinaunix.net/uid-23069658-id-4028681.html 学习到了一个阶段之后,就需要不断的总结.沉淀.清零,然后才能继续“上路”.回想起自己当年刚 ...

  6. 转:谈谈Linux下动态库查找路径的问题

    http://blog.chinaunix.net/uid-23069658-id-4028681.html 学习到了一个阶段之后,就需要不断的总结.沉淀.清零,然后才能继续“上路”.回想起自己当年刚 ...

  7. Linux下c函数dlopen实现加载动态库so文件代码举例

    dlopen()是一个强大的库函数.该函数将打开一个新库,并把它装入内存.该函数主要用来加载库中的符号,这些符号在编译的时候是不知道的.这种机制使得在系统中添加或者删除一个模块时,都不需要重新编译了. ...

  8. Linux 下动态库 / 静态库(依赖)

    一. 依赖动态库的动态库 libfun.so依赖动态库libtest.so(libfun.so动态库里的函数intnothing()调用了libtest.so里的intmytest()函数),而mai ...

  9. Linux下动态库生成和使用

    Linux下动态库生成和使用 一.动态库的基本概念 1.动态链接库是程序运行时加载的库,当动态链接库正确安装后,所有的程序都可以使用动态库来运行程序.动态链接库是目标文件的集合,目标文件在动态链接库中 ...

随机推荐

  1. 浅谈checkpoint与内存缓存

    事务日志存在检查点checkpoint,把内存中脏数据库写入磁盘,以减少故障恢复的时间,在此之前有必要提下SQL Server内存到底存放了哪些数据? SQL Server内存使用 对SQL Serv ...

  2. C++ Const引用详解

    (1)       在实际的程序中,引用主要被用做函数的形式参数--通常将类对象传递给一个函数.引用必须初始化. 但是用对象的地址初始化引用是错误的,我们可以定义一个指针引用. 1 int ival ...

  3. 1.交通聚类:编辑距离 (Levenshtein距离)Java实现

    1.最近工作中要实现用户车辆的行驶路线的聚类,由于所给的数据只有用户一天中交通卡口所监视的卡口名称 :即青岛路-威海路-济阳路 . 要通过聚类实现车辆路线的规律分析,首先要解决的是相似度问题,我们知道 ...

  4. C#入门随手笔记

    1..Net Framework是Microsoft为开发应用程序而创建的一个开发平台. 运行操作系统不限:Microsoft版本运行在windows,Mono版本运行开Linux和MacOS: 应用 ...

  5. Handler Should be static or leaks Occur?

    解决办法: public class SampleActivity extends Activity { /** * Instances of static inner classes do not ...

  6. http之错误码

    http://en.wikipedia.org/wiki/List_of_HTTP_status_codes 响应码由三位十进制数字组成,它们出现在由HTTP服务器发送的响应的第一行.响应码分五种类型 ...

  7. Code First03---CodeFirst根据配置同步到数据库的三种方式

    上一节我们说到使用Fluent API对实体的配置,但是有一个问题了,在业务中我们可以用到的实体很多,那是不是每个都需要这样去配置,这样就造成我们重写的OnModelCreating方法很庞大了.所以 ...

  8. c语言小知识点

    大一时学c语言,总结的一些自己感觉很零碎且容易忘的知识点,不对之处请指正 1.字符串不管中间是否有数值0,结尾一定有数值02.浮点类型的变量存储并不精确3.printf格式串自动右对齐,加负号左对齐4 ...

  9. jQuery学习:用按键移动方块

    <!doctype html> <html> <head> <meta charset="utf-8"> <style typ ...

  10. GNU KHATA——开源的会计管理软件

    导读 GNU Khata是一个会计工具. 或者,我应该说成是一系列的会计工具集合,它就像经济管理方面的Evernote一样.它的应用是如此之广,以至于它不但可以用于个人的财务管理,也可以用于大型公司的 ...