.so link linux
2010-03-31 09:43:00 miaojian_430 阅读数 218

还没填写内容  改天找到合适的再添吧

linux so
2017-04-05 15:03:28 kokiafans 阅读数 2
http://mypyg.iteye.com/blog/845915

牵扯到ELF格式,gcc编译选项待补,简单实用的说明一下,对Linux下的so文件有个实际性的认识。
1.so文件是什么?
2.怎么生成以及使用一个so动态库文件?
3.地址空间,以及线程安全.
4.库的初始化,解析:
5.使用我们自己库里的函数替换系统函数:
//-------------------------------------------------------------------------------
1.so文件是什么?
也是ELF格式文件,共享库(动态库),类似于DLL。节约资源,加快速度,代码升级简化。
知道这么多就够了,实用主义。等有了印象再研究原理。
2.怎么生成以及使用一个so动态库文件?
先写一个C文件:s.c
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
C代码 收藏代码
#ifndef _MY_SO_HEADER_
#define _MY_SO_HEADER_
void out_msg(const char *m);
#endif

再来一个C文件来引用这个库中的函数:ts.c
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文件:
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(可以自己写个内存泄露检测工具了)
C代码 收藏代码
#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
C代码 收藏代码
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工作了。
暂时就想到这么多了。
2018-07-25 19:10:00 weixin_33825683 阅读数 5

Linux Library Types:

There are two Linux C/C++ library types which can be created:

  • Static libraries (.a):
    Library of object code which is linked with, and becomes part of the application.
  • Dynamically linked shared object libraries (.so):
    There is only one form of this library but it can be used in two ways.
    Dynamically linked at run time. The libraries must be available during compile/link phase. The shared objects are not included into the executable component but are tied to the execution.
    Dynamically loaded/unloaded and linked during execution (i.e. browser plug-in) using the dynamic linking loader system functions.

A .a file is a static library, while a .so file is a shared object dynamic library similar to a DLL on Windows.
A .a can included as part of a program during the compilation & .so can imported, while a program loads.

.a是静态库。
.so是动态库。

When you link against the *.a, the code from the library is included in the executable itself and the executable can be run without requiring the *.a file to be present.
When you link against the *.so, that is not the case and the *.so file must be present at runtime.

.a的方式,.a中的内容是包含在二进制文件中的,所以二进制文件运行的时候不需要*.a file。

Static Libraries: (.a)

As a follow on, a .a file is an "ar" archive.
Not unlike a tar archive, it stores .o or object files, allowing them to be pulled out of the archive, and linked into a program, among other things. You could use ar to store other files if you wanted.

Create library "libctest.a"
ar -cvq libctest.a ctest1.o ctest2.o
get a listing of the members of an ar file

You can get a listing of the members of an ar file with the -t parameter, for instance:

linux下,在ffmpeg目录下

 ar -t libavformat/libavformat.a

运行结果:

[root@localhost libavformat]# ar -t libavformat.a
3dostr.o
...
mov.o
...
yuv4mpegdec.o
yuv4mpegenc.o
Linking with the library
cc -o executable-name prog.c libctest.a
cc -o executable-name prog.c -L/path/to/library-directory -lctest

Dynamically Linked "Shared Object" Libraries: (.so)

A .so file is a "shared object" file, and has a lot more information available to the linker so that members can be linked in to a loading program as rapidly as possible.

References:

https://stackoverflow.com/questions/12293530/what-is-the-difference-between-so-and-a-files
https://unix.stackexchange.com/questions/13192/what-is-the-difference-between-a-and-so-file
http://www.yolinux.com/TUTORIALS/LibraryArchives-StaticAndDynamic.html

linux so
2017-04-05 15:03:28 u010359663 阅读数 8
http://mypyg.iteye.com/blog/845915

牵扯到ELF格式,gcc编译选项待补,简单实用的说明一下,对Linux下的so文件有个实际性的认识。
1.so文件是什么?
2.怎么生成以及使用一个so动态库文件?
3.地址空间,以及线程安全.
4.库的初始化,解析:
5.使用我们自己库里的函数替换系统函数:
//-------------------------------------------------------------------------------
1.so文件是什么?
也是ELF格式文件,共享库(动态库),类似于DLL。节约资源,加快速度,代码升级简化。
知道这么多就够了,实用主义。等有了印象再研究原理。
2.怎么生成以及使用一个so动态库文件?
先写一个C文件:s.c
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
C代码 收藏代码
#ifndef _MY_SO_HEADER_
#define _MY_SO_HEADER_
void out_msg(const char *m);
#endif

再来一个C文件来引用这个库中的函数:ts.c
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文件:
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(可以自己写个内存泄露检测工具了)
C代码 收藏代码
#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
C代码 收藏代码
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工作了。
暂时就想到这么多了。
2012-07-23 14:23:45 panfengsoftware 阅读数 508

提起Dynamically linked,则要归结到库的概念和应用了,所以我就系统地了解了一下子,并愿意贴出来,跟大家一起分享。

库的目的是将类似的功能封装在一个单元集中。这些单元可以被其他开发人员共享,并称其为模块化编程,也就是说从模块中编译程序。Linux支持两种类型的库,每种都有自己的优点和缺点。静态库在编译程序时,将库中相应的功能绑定到程序中;然而动态库则不同,它是当程序在运行时才被加载的。图1显示了linux库的层次结构。

图1 linux库的层次结构

你可以通过两种方式来使用共享库的:要么在程序运行时动态地链接,要么在用户的控制下进行动态地加载。这篇文章将讨论着两种方式。

静态库对于功能少的小程序中是有益的。然而对于需要多个库的程序来说,共享库则可以减少程序的内存占用(包括磁盘上的和运行时的内存)。这是因为多个程序可以同时使用一个共享库,因此在一个时间,内存中只需要保留一个共享库的副本即可。使用静态库,每一个正在运行的程序库都有个库的副本。

GNU / Linux提供两种方法来处理共享库(每个方法都是Sun Solaris起源)。你可以动态链接共享库,并在执行时,使用Linux系统加载库(除非它已经在内存中了)。另一种方案是有选择性地调用进程中的库函数,被称为动态加载。采用动态加载,程序可以加载一个特定的库(除非已经加载),然后调用该库中的某一特定功能。 (图2显示了这两种方法。)这是在建立支持插件的应用程序时所共同使用的模式。

图2 动态链接

Linux的动态链接

现在,让我们深入探讨了在Linux中使用动态链接的共享库的过程。当用户启动应用程序时,它们是调用一个可执行的和链接格式(ELF)的镜像。内核始于加载ELF映像到用户空间的虚拟内存的过程。内核注意到一个名为ELF段,被称为.interp,这表明动态链接器要被使用(/lib/ld-linux.so),如清单1所示。这类似于在UNIX中所解释定义的脚本文件(#!/bin/sh):只是在不同的上下文中使用。

注意:ld-linux.so(elf动态库的装载器)

清单1 使用只readelf命令来展示程序的头文件

mtj@camus:~/dl$ readelf -l dl

Elf file type is EXEC (Executable file)

  Entry point 0x8048618

  There are 7 program headers, starting at offset 52

  Program Headers:

  Type           Offset   VirtAddr    PhysAddr   FileSiz MemSiz  Flg Align

  PHDR           0x000034 0x08048034 0x08048034  0x000e0 0x000e0 R E 0x4

  INTERP         0x000114 0x08048114 0x08048114 0x00013  0x00013 R   0x1

  [Requesting program interpreter: /lib/ld-linux.so.2]

  LOAD           0x000000 0x08048000 0x08048000 0x00958  0x00958 R E 0x1000

  LOAD           0x000958 0x08049958 0x08049958  0x00120 0x00128 RW  0x1000

  DYNAMIC        0x00096c 0x0804996c  0x0804996c 0x000d0 0x000d0 RW  0x4

  NOTE           0x000128 0x08048128 0x08048128  0x00020 0x00020 R   0x4

  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000  0x00000 RW  0x4

  ...

  mtj@camus:~dl$

请注意,ld-linux.so本身就是一个ELF共享库,但它是静态编译的,并不依赖于共享库。当需要动态链接时,内核自动启动动态链接器(ELF解释器),它先初始化自身,然后加载指定的共享对象(除非已加载)。之后,它执行必要的再定位,包括目标共享对象所使用的共享对象。 LD_LIBRARY_PATH环境变量定义了可用的共享对象的路径。完成后,控制权转移回原来的程序,开始执行。 

Linxu中的动态加载

其实Linux会为给定的程序自动装载和链接库,它可以分享这个应用程序本身的控制。在这种情况下,这一过程被称为动态加载。有了动态加载,应用程序可以指定一个特定的库来加载,然后将其作为一个可执行库来使用(即调用其中的函数)。然而,正如你前边所学,共享库动态加载功能,只不过是一个标准的共享库(ELF共享对象)。事实上,ld-linux动态链接作为ELF加载器和解释器仍然参与了这项工作的过程。 
动态加载(DL)的API可以动态加载共享库,并允许将其提供给用户空间的程序。API虽然小,但是它提供程序需要的所有东西,并在程序执行背后做了好多工作,完整的API见表1。

表1 完整的API


Function

Description

dlopen

打开一个动态链接库

dlsym

获取所打开文件对象的描述符地址

dlerror

返回最后一次发生错误的信息字符串

dlclose

Closes an object file关闭一个文件对象











linux so

阅读数 15

linux so

阅读数 270

没有更多推荐了,返回首页