实验 编译和链接-编写自己的链接库【操作系统】

实验 编译和链接-编写自己的链接库

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.例子

完成编译链接那点事的例子。

静态链接库

实验 编译和链接-编写自己的链接库【操作系统】_操作系统_02

[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]#

实验 编译和链接-编写自己的链接库【操作系统】_动态链接库_03

动态链接库

[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]#

实验 编译和链接-编写自己的链接库【操作系统】_centos_04

[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]#

实验 编译和链接-编写自己的链接库【操作系统】_centos_05

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]#

实验 编译和链接-编写自己的链接库【操作系统】_centos_06

源码

// 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;

}