mirror of
https://github.com/LCTT/TranslateProject.git
synced 2025-02-25 00:50:15 +08:00
Update 20220603 How static linking works on Linux.md
This commit is contained in:
parent
5e4de1e246
commit
7d6b4b770f
@ -15,26 +15,26 @@ Linux 静态链接工作原理
|
|||||||
|
|
||||||
图片作者:Mapbox Uncharted ERG, [CC-BY 3.0 US][2]
|
图片作者:Mapbox Uncharted ERG, [CC-BY 3.0 US][2]
|
||||||
|
|
||||||
使用 C 编写的应用程序代码通常有多个源代码文件,但是,你需要将它们最终编译到一个单个的可执行文件。
|
使用 C 编写的应用程序时,通常有多个源码文件,但最终您需要编译成单个的可执行文件。
|
||||||
|
|
||||||
你可以通过两种方式来完成这项工作:通过创建一个 <ruby>静态<rt>static</rt></ruby> 库 或 一个 <ruby>动态<rt>dynamic</rt></ruby> 库 (也被称为 <ruby>共享<rt>shared</rt></ruby> 库)。这两种类型的库在从它们是如何创建和链接的角度来看是不同的。你选择使用哪种方式取决于你的的具体使用情况。
|
你可以通过两种方式来完成这项工作:通过创建一个 <ruby>静态<rt>static</rt></ruby> 库 或 一个 <ruby>动态<rt>dynamic</rt></ruby> 库 (也被称为 <ruby>共享<rt>shared</rt></ruby> 库)。从创建和链接的方式来看,它们是两种不同类型的库。选择使用哪种方式取决于你的的具体场景。
|
||||||
|
|
||||||
在 [上一篇文章][3] 中,我演示了如何创建一个动态链接的可执行文件,这是一种更常用的方法。在这篇文章中,我将解释如何创建一个静态链接的可执行文件。
|
在 [上一篇文章][3] 中,我演示了如何创建一个动态链接的可执行文件,这是一种更通用的方法。在这篇文章中,我将说明如何创建一个静态链接的可执行文件。
|
||||||
|
|
||||||
### 链接器使用静态库
|
### 使用静态库链接器
|
||||||
|
|
||||||
链接器是一个命令,它将一个程序的数个部分组合到一起,并为它们重新组织存储器分配。
|
链接器是一个命令,它将一个程序的多个部分组合,并为它们重新组织存储器分配。
|
||||||
|
|
||||||
链接器的功能包括:
|
链接器的功能包括:
|
||||||
|
|
||||||
* 集成一个程序的所有的部分
|
* 集成一个程序的所有的部分
|
||||||
* 计算组织出一个新的存储器结构,以便所有的部分组合在一起
|
* 装配一个新的存储器结构,以便所有的部分组合在一起
|
||||||
* 重新复活存储器地址,以便程序可以在新的存储器组织下运行
|
* 恢复存储器地址,以便程序可以在新的存储器组织下运行
|
||||||
* 解析符号引用
|
* 解析符号引用
|
||||||
|
|
||||||
作为这些链接器功能的结果,创建了一个名称为可执行文件的一个可运行程序。
|
经过这些链接器功能,创建了一个名称为可执行文件的一个可运行程序。
|
||||||
|
|
||||||
静态库是通过复制一个程序中的所有必须的库模块到最终的可执行镜像来创建的。链接器将链接静态库作为编译过程的最后一步。可执行文件是通过解析外部引用、库实例程序与程序代码组合来创建的。
|
静态库是通过复制一个程序中的所有依赖库模块到最终的可执行镜像来创建的。链接器将链接静态库作为编译过程的最后一步。可执行文件是通过解析外部引用、库实例程序与程序代码组合来创建的。
|
||||||
|
|
||||||
### 创建对象文件
|
### 创建对象文件
|
||||||
|
|
||||||
@ -71,7 +71,7 @@ return (a/b);
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
现在,使用 GCC 来参加对象文件 `add.o` 、`sub.o` 、`mult.o` 和 `divi.o` :
|
现在,使用 GCC 来生成对象文件 `add.o` 、`sub.o` 、`mult.o` 和 `divi.o` :
|
||||||
|
|
||||||
```
|
```
|
||||||
$ gcc -c add.c sub.c mult.c divi.c
|
$ gcc -c add.c sub.c mult.c divi.c
|
||||||
@ -88,7 +88,7 @@ $ ls
|
|||||||
add.c divi.c libmymath.a mult.c mymath.h sub.c
|
add.c divi.c libmymath.a mult.c mymath.h sub.c
|
||||||
```
|
```
|
||||||
|
|
||||||
现在,你已经创建了一个简单的名称为 `libmymath` 是示例数学库,你可以在 C 代码中使用它。当然,这里有非常复杂的 C 库,这就是他们这些开发者来生成最终产品的工艺流程,你和我可以安装这些库并在 C 代码中使用。
|
现在,你已经创建了一个简单的名称为 `libmymath` 是数学示例库,你可以在 C 代码中使用它。当然,这里有非常复杂的 C 库,这就是开发者们用于开发最终产品的过程,你和我可以安装这些库并在 C 代码中使用。
|
||||||
|
|
||||||
接下来,在一些自定义代码中使用你的数学库,然后链接它。
|
接下来,在一些自定义代码中使用你的数学库,然后链接它。
|
||||||
|
|
||||||
@ -129,9 +129,9 @@ int main()
|
|||||||
$ gcc -I . -c mathDemo.c
|
$ gcc -I . -c mathDemo.c
|
||||||
```
|
```
|
||||||
|
|
||||||
`-I` 选项告诉 GCC 来搜索在其后列出的头文件。在这个实例中,你正在具体指定当前目录,通过一个单个点 (`.` ) 来表示。
|
`-I` 选项告诉 GCC 搜索在其后列出的头文件。在这个实例中,你通过单个点 (`.` ) 来指定当前目录。
|
||||||
|
|
||||||
Link `mathDemo.o` with `libmymath.a` 来参加最终的可执行文件。这里有两种方法来向 GCC 表达这一点。
|
连接 `mathDemo.o` 和 `libmymath.a` 来生成最终的可执行文件。这里有两种方法来向 GCC 表达这一点。
|
||||||
|
|
||||||
你可以指向文件:
|
你可以指向文件:
|
||||||
|
|
||||||
@ -139,17 +139,17 @@ Link `mathDemo.o` with `libmymath.a` 来参加最终的可执行文件。这里
|
|||||||
$ gcc -static -o mathDemo mathDemo.o libmymath.a
|
$ gcc -static -o mathDemo mathDemo.o libmymath.a
|
||||||
```
|
```
|
||||||
|
|
||||||
或者,你可以具体指定库的路径和库的名称:
|
或者,你可以具体指定库的路径及名称:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ gcc -static -o mathDemo -L . mathDemo.o -lmymath
|
$ gcc -static -o mathDemo -L . mathDemo.o -lmymath
|
||||||
```
|
```
|
||||||
|
|
||||||
在后面的那个示例中,`-lmymath` 选项告诉链接器来链接随对象文件 `mathDemo.o` 出现的对象文件 `libmymath.a` 来创建最终的可执行文件。`-L` 选项指示链接器在下面的参数中查找库 (类似于你使用 `-I` 所做的工作)。
|
在后面的那个示例中,`-lmymath` 选项告诉链接器来链接随对象文件 `mathDemo.o` 中的对象文件 `libmymath.a` 来生成最终的可执行文件。`-L` 选项指示链接器在下面的参数中查找库 (类似于你使用 `-I` 所做的工作)。
|
||||||
|
|
||||||
### 分析结果
|
### 分析结果
|
||||||
|
|
||||||
使用 `file` 命令来确认它是静态链接的:
|
使用 `file` 命令来验证它是静态链接的:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ file mathDemo
|
$ file mathDemo
|
||||||
@ -164,7 +164,7 @@ $ ldd ./mathDemo
|
|||||||
not a dynamic executable
|
not a dynamic executable
|
||||||
```
|
```
|
||||||
|
|
||||||
你也可以检查 `mathDemo` 可执行文件的大小:
|
你也可以查看 `mathDemo` 可执行文件的大小:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ du -h ./mathDemo
|
$ du -h ./mathDemo
|
||||||
@ -193,9 +193,9 @@ Enter two numbers
|
|||||||
|
|
||||||
动态链接可执行文件通常优于静态链接可执行文件,因为动态链接会保持应用程序的组件模块化。假如一个库接收到一次关键安全更新,那么它可以很容易地修补,因为它存在于应用程序的外部。
|
动态链接可执行文件通常优于静态链接可执行文件,因为动态链接会保持应用程序的组件模块化。假如一个库接收到一次关键安全更新,那么它可以很容易地修补,因为它存在于应用程序的外部。
|
||||||
|
|
||||||
当你使用静态链接时,库的代码会 "隐藏" 在你创建的可执行文件之中,意味着在库每次更新时(相信我,你会有更好的东西),仅有的一种修补它的方法是重新编译和重新发布一个新的可执行文件。
|
当你使用静态链接时,库的代码会 "隐藏" 在你创建的可执行文件之中,意味着在库每次更新时(相信我,你会有更好的东西),仅有的一种修补方法是重新编译和发布一个新的可执行文件。
|
||||||
|
|
||||||
不过,如果一个库的代码,要么存在于它正在使用的具有相同代码的可执行文件中,要么存在于专用的预期不会接收到任何更新的嵌入式设备中,那么静态连接将是一种可接受的选项。
|
不过,如果一个库的代码,要么存在于它正在使用的具有相同代码的可执行文件中,要么存在于不会接收到任何更新的专用嵌入式设备中,那么静态连接将是一种可接受的选项。
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user