实验 编译和链接-编写自己的链接库
1.深刻理解编译和链接到底做什么?
大家肯定都知道计算机程序设计语言通常分为机器语言、汇编语言和高级语言三类。高级语言需要通过翻译成机器语言才能执行,而翻译的方式分为两种,一种是编译型,另一种是解释型,因此我们基本上将高级语言分为两大类,一种是编译型语言,例如C,C++,Java,另一种是解释型语言,例如Python、Ruby、MATLAB 、JavaScript。
如何将高层的C/C++语言编写的程序转换成为处理器能够执行的二进制代码的过程,包括四个步骤:
预处理(Preprocessing)
编译(Compilation)
汇编(Assembly)
链接(Linking)
更详细的信息参考 Linux 程序编译过程的来龙去脉
2.静态链接库和动态链接库
什么是链接?我们引用CSAPP的定义:链接(linking)是将各种代码和数据部分收集起来并组合成为一个单一文件的过程,这个文件可被加载(或被拷贝)到存储器并执行。
需要强调的是,链接可以执行于编译时(compile time),也就是在源代码被翻译成机器代码时;也可以执行于加载时,也就是在程序被加载器(loader)加载到存储器并执行时;甚至执行于运行时(run time),由应用程序来执行。
说了这么多,了解链接有什么用呢?生命这么短暂,我们干嘛要去学习一些根本用不到的东西。当然有用了,继续引用CSAPP的说法,如下:
理解链接器将帮助你构造大型程序。
理解链接器将帮助你避免一些危险的编程错误。
理解链接将帮助你理解语言的作用域是如何实现的。
理解链接将帮助你理解其他重要的系统概念。
理解链接将使你能够利用共享库。 ……
编辑器系统提供了一种机制,将所有的编译出来的目标文件打包成一个单独的文件,叫做静态库(static library)。当链接器和静态库链接的时候,链接器会从这个打包的文件中“解压缩”出需要的部分目标文件进行链接。这样就解决了资源浪费的问题。
动态链接库/共享库是一个目标模块,在运行时可以加载到任意的存储器地址,并和一个正在运行的程序链接起来。这个过程就是动态链接(dynamic linking),是由一个叫做动态链接器(dynamic linker)的程序完成的。
参看编译链接那点事,完成该文中的例子
3. 编写自己的链接库和动态链接库
上一章我们编写了生产者-消费者问题的同步代码,按照上一步文中的例子,对其代码进行改造,写出自己的静态链接库和动态链接库,并对其进行调用。
略
4. 用readelf 命令查看可执行文件的格式。
查看elf中增加了自己的动态链接库和静态链接库的差异,并截图给予说明。
实验
1.例子
完成编译链接那点事的例子。
静态链接库
[root@centos-7 jsss-13]# touch swap.c [root@centos-7 jsss-13]# touch add.c [root@centos-7 jsss-13]# touch calc.h [root@centos-7 jsss-13]# gcc add.c -c -o add.o [root@centos-7 jsss-13]# gcc swap.c -c -o swap.o [root@centos-7 jsss-13]# ls add.c add.o calc.h swap.c swap.o [root@centos-7 jsss-13]# ar rcs libcalc.a swap.o add.o [root@centos-7 jsss-13]# ls add.c add.o calc.h libcalc.a swap.c swap.o [root@centos-7 jsss-13]#
[root@centos-7 jsss-13]# touch test.c [root@centos-7 jsss-13]# gcc test.c ./libcalc.a -o test [root@centos-7 jsss-13]# ./test 2 1 [root@centos-7 jsss-13]#
动态链接库
[root@centos-7 jsss-13_2]# gcc swap.c add.c -shared -o libcalc.so [root@centos-7 jsss-13_2]# gcc test.c -o test ./libcalc.so [root@centos-7 jsss-13_2]# ./test 2 1 [root@centos-7 jsss-13_2]#
[root@centos-7 jsss-13_2]# ldd ./test linux-vdso.so.1 => (0x00007ffde939a000) ./libcalc.so (0x00007ff3026dc000) libc.so.6 => /lib64/libc.so.6 (0x00007ff30230e000) /lib64/ld-linux-x86-64.so.2 (0x00007ff3028de000) [root@centos-7 jsss-13_2]#
2.作业
自己写一个链接库,添加一个运算符@,完成a@b=a+2b的功能。
结果
[root@centos-7 jsss-13_3]# gcc add1.c -c -o add1.o [root@centos-7 jsss-13_3]# ar rcs libcalc.a add1.o [root@centos-7 jsss-13_3]# gcc test.c ./libcalc.a -o test [root@centos-7 jsss-13_3]# ./test 5 1 2 [root@centos-7 jsss-13_3]#
源码
// add1.c int add1(int a, int b) { return a + 2*b; }
// calc.h #ifndef CALC_H_ #define CALC_H_ #ifdef _cplusplus extern "C" { #endif int add1(int,int); #ifdef _cplusplus } #endif #endif // CALC_H_
#include <stdio.h> #include <stdlib.h> #include "calc.h" int main(int argc, char *argv[]) { int a = 1, b = 2; int c=add1(a, b); printf("%d %d %d\n",c,a, b); return EXIT_SUCCESS; }