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

牵扯到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 

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

-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

 #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,懒得弄长了)

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(100);  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 什么是SO文件相关推荐

  1. Windows与Linux之间互传文件的方法

    以下方法均是以Windows为操作机: 1. 通过WinSCP: WinSCP是一款开源的SFTP客户端,运行于Windows系统下,遵照GPL发布.WinSCP除了SFTP,还支持SSH.SCP(S ...

  2. Linux 下高级日志文件查看器Log File Navigator

    Log File Navigator,简称lnav,是一款面向小规模的适用于 Linux 的高级日志文件查看器.它是一个终端应用程序,可以理解您的日志文件,让您轻松找到问题,几乎不需要什么设置. ln ...

  3. 如何快速清空 Linux 中的大文件

    本文总结了几种快速清空Linux中的大文件方法,快来看看对你有帮助吗? 1. 通过重定向到null清空文件内容 使用 shell 重定向null(不存在的对象)到文件的最简单方法来清空文件内容 # & ...

  4. python linux编程与window编程_Python实现Windows和Linux之间互相传输文件(文件夹)的方法...

    项目中需要从Windows系统传输ISO文件到Linux测试系统,然后再Linux测试系统里安装这个ISO文件.所以就需要实现如何把文件从Windows系统传输到Linux系统中. 在项目中使用了ps ...

  5. Linux 中 3 个文件打包上传和下载相关命令详解

    tar 命令 通过 SSH 访问服务器,难免会要用到压缩,解压缩,打包,解包等,这时候tar 命令就是必不可少的一个功能强大的工具.Linux 中最流行的tar是麻雀虽小,五脏俱全,功能强大. 使用t ...

  6. linux系统中的文件传输

    Linux系统中的文件传输 1 实验环境 2 scp命令 3 rsync命令 3.1 rsync和scp命令对比 3.2 rsync命令用法 4 文件的归档压缩 4.1 文件归档 4.2 文件压缩 4 ...

  7. linux 中如何将文件粘贴到usr下的lib内,学会在Linux下GCC生成和使用静态库和动态库...

    一.基本概念1.1什么是库 在windows平台和linux平台下都大量存在着库. 本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行. 由于windows和linux的平台不同(主 ...

  8. linux下编译make文件报错“/bin/bash^M: 坏的解释器,使用grep快速定位代码位置

    一.linux下编译make文件报错"/bin/bash^M: 坏的解释器 参考文章:http://blog.csdn.net/liuqiyao_01/article/details/415 ...

  9. Linux解压WINRAR文件

    windows平台很多压缩文档为rar文件,那么怎么做到Linux解压rar文件(unrar安装和使用)? 简单,centos5安装unrar即可. unrar安装方法如下: wget  http:/ ...

  10. linux下删除乱码文件

    为什么80%的码农都做不了架构师?>>>    在linux下对于每个文件都一个对应的不变的inode号,使用 ls -li 可以查看到文件的inode号,同时find可以根据ino ...

最新文章

  1. Mybatis Plus 是如何实现动态 SQL 语句的?原理你懂吗?
  2. 剑指offer七:斐波那契数列
  3. Exception in thread main java.lang.NoClassDefFoundError: org/apache/tez/dag/api/TezConfiguration
  4. tp5分布式redis_TP5通过缓存数据到Redis
  5. zoj 1789 The Suspects
  6. web-attack 1-5视频汇总
  7. Netty : netty 4如何解决空轮询bug
  8. 对fragment的学习
  9. office插件开发_Office神插件,打开新世界的大门
  10. groovy入门(2-1)Groovy的Maven插件安装:Plugin execution not covered by lifecycle configuration...
  11. html中怎么加入动态图片,视频加动态水印 怎么在视频画面中添加一个gif动态图片水印...
  12. java aes解密源码_java AES解密,用易语言实现
  13. 网页版微信自动群发消息
  14. ROS机器人操作系统教学与应用的思考
  15. 洛谷p2655 2038年问题 普及/提高- 模拟
  16. 命令行工具(Command line tools)
  17. 管理学计算机要求,[管理学]计算机第一章.ppt
  18. 映客都是互刷礼物吗_今日网红
  19. 洛谷·幼儿园篮球题【including范德蒙德卷积,二项式反演
  20. 【三维语义分割】PointNet详解(一)

热门文章

  1. 开源WebMail客户端Intouch2.2beta导致IE6崩溃的原因和修改方法
  2. 多元统计分析基于r课后答案_应用多元统计分析课后答案.doc
  3. 联想笔记本修复计算机还原系统失败,联想笔记本电脑重装系统不成功,联想笔记本系统恢复...
  4. 单径瑞利信道中的BPSK相干解调的(理论)误码率性能
  5. Blockchain -Corda框架研究一 sendfile-Attachments学习笔记
  6. 【总结】EJB开发过程中遇到的几个问题
  7. 新人必看第一帖,BT3和BT4傻瓜版使用!附:BT4中文版下载
  8. 惠普T5325 惠普T5565 惠普T5400 瘦客机评测
  9. Qt 中Socket编程实例
  10. Android性能优化最佳实践,分享一点面试小经验