第49部分- Linux x86 64位汇编 创建静态库和动态库
如果为每个汇编语言函数创建单独的目标文件,会导致文件数量剧增。
可以通过使用库来简化汇编函数的目标文件问题。
GNC的C编译器可以不在命令行中独立的包含每个单独的函数目标文件,允许把所有目标文件组合在单一存档文件中。当编译C主程序时,要做的所有工作就是包含单一的目标存档文件。
存档文件可以用于编译任何使用存档文件中包含的任何函数的程序,这种存档文件就是库文件library file.
经常按照应用程序类型或者函数类型把函数分组在一起,单一应用程序项目中可以使用多个库文件。
库文件中包含的目标代码被编译器编译到了主程序中,这类库文件成为静态文件。函数的目标代码被编译到可执行代码中之后,可执行程序的运行就不需要库文件了。这样每个程序都包含了函数的代码。
在linux中使用ar命令创建静态文件。
Ar的命令行选项如下:
可以用一个或多个修饰符修改基本选项:
创建静态库
Linux操作系统中的静态库命名为libx.a
其中x是库的名称。
我们将C调用汇编中的几个文件汇编成一个静态文件。
先生成目标文件:
as -o square.o square.s
as -o areafunc.o areafunc.s
as -o cpuidfunc.o cpuidfunc.s
生成库文件:
ar -r liblearn.a square.o areafunc.o cpuidfunc.o
通过tv参数可以查看
ar -tv liblearn.a
创建库文件后,可以创建库的索引来帮助必须和库连接的其他程序的编译速度。
ranlib liblearn.a
可以通过nm命令来查看库文件中的函数的符号
nm liblearn.a
使用静态库
然后我们重新编译之前的函数:
gcc -o inttest inttest.c square.s
现在使用静态编译库编译命令如下:
gcc -o intest inttest.c liblearn.a
两者编译出来的大小是一样的。
创建动态库
我们知道windows中的动态库是DLL文件。
在Linux里面就是.so文件。
在说明动态库之前,我们来看下为什么要用动态库。
静态文件的优缺点
- 库文件已修改,所有依赖此函数的应用程序都要重新编译。强耦合。
- 程序要包含使用到的每个函数代码,程序会变大。浪费空间。
- 多个程序使用相同的函数,都需要将该函数 加载到内存,浪费内存。
共享库就是解决这些问题的,它包含函数目标代码的单独文件,被加载到操作系统的通用区域中。当应用程序需要访问共享库中的函数时,操作系统自动把函数代码加载到内存中,并且允许应用程序访问它。
创建共享库
Linux对共享库的命名约定是libx.so
X是库名称,扩展名.so是表示共享库。
根据上面的3个汇编文件我们创建一个共享库
gcc -shared -o liblearn.so square.o areafunc.o
gcc -shared -fPIC -o liblearn.so square.o areafunc.o
这里去掉了cpuidfunc函数,因为该汇编文件不符合动态库要求。
也可以使用nm进行查看。
nm -D liblearn.so
使用共享库
还是以之前的inttest.c文件为例,之前的编译命令为:
gcc -o inttest inttest.c square.s
动态库的编译方式如下:
gcc -o inttest -L. -llearn inttest.c
或者如下:
gcc inttest.c liblearn.so -o inttest
我们要知道动态库不会编译到C程序中,但是编译器需要知道如何访问函数,使用-l选项加上共享库的名称(减去lib部分和.so扩展名)。使用-L选项通知编译器在哪里查找它。如果共享库位于和程序文件相同的目录中,可以使用本地的目录。
反汇编后,我们可以发现可执行文件中不包含函数代码。
另外可以使用ldd命令来查看可执行文件依赖什么共享库。
# ldd inttest
linux-vdso.so.1 (0x00007ffcafbe0000)
liblearn.so => /root/liblearn.so (0x00007fcb5c89b000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fcb5c4aa000)
/lib64/ld-linux-x86-64.so.2 (0x00007fcb5cc9f000)
共享库的程序的变量
动态加载器访问动态库的方法有两种:
- LD_LIBRARY_PATH
- /etc/ld.so.conf文件
例如 export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:."
/etc/ld.so.conf文件保存动态加载器在哪些目录中查找库的目录清单,主要是系统动态库。
修改后需要执行ldconfig进行加载。