mirror of
https://github.com/LCTT/TranslateProject.git
synced 2024-12-23 21:20:42 +08:00
Translated
This commit is contained in:
parent
57ebfb7eb6
commit
2c08ba411f
@ -1,217 +0,0 @@
|
||||
[#]: subject: "How static linking works on Linux"
|
||||
[#]: via: "https://opensource.com/article/22/6/static-linking-linux"
|
||||
[#]: author: "Jayashree Huttanagoudar https://opensource.com/users/jayashree-huttanagoudar"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: "robsean"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
How static linking works on Linux
|
||||
======
|
||||
Learn how to combine multiple C object files into a single executable with static libraries.
|
||||
|
||||
![Woman using laptop concentrating][1]
|
||||
|
||||
Image by Mapbox Uncharted ERG, [CC-BY 3.0 US][2]
|
||||
|
||||
Code for applications written using C usually has multiple source files, but ultimately you will need to compile them into a single executable.
|
||||
|
||||
You can do this in two ways: by creating a static library or a dynamic library (also called a shared library). These two types of libraries vary in terms of how they are created and linked. Your choice of which to use depends on your use case.
|
||||
|
||||
In a [previous article][3], I demonstrated how to create a dynamically linked executable, which is the more commonly used method. In this article, I explain how to create a statically linked executable.
|
||||
|
||||
### Using a linker with static libraries
|
||||
|
||||
A linker is a command that combines several pieces of a program together and reorganizes the memory allocation for them.
|
||||
|
||||
The functions of a linker include:
|
||||
|
||||
* Integrating all the pieces of a program
|
||||
* Figuring out a new memory organization so that all the pieces fit together
|
||||
* Reviving addresses so that the program can run under the new memory organization
|
||||
* Resolving symbolic references
|
||||
|
||||
As a result of all these linker functionalities, a runnable program called an executable is created.
|
||||
|
||||
Static libraries are created by copying all necessary library modules used in a program into the final executable image. The linker links static libraries as a last step in the compilation process. An executable is created by resolving external references, combining the library routines with program code.
|
||||
|
||||
### Create the object files
|
||||
|
||||
Here's an example of a static library, along with the linking process. First, create the header file `mymath.h` with these function signatures:
|
||||
|
||||
```
|
||||
int add(int a, int b);
|
||||
int sub(int a, int b);
|
||||
int mult(int a, int b);
|
||||
int divi(int a, int b);
|
||||
```
|
||||
|
||||
Create `add.c`, `sub.c` , `mult.c` and `divi.c` with these function definitions:
|
||||
|
||||
```
|
||||
// add.c
|
||||
int add(int a, int b){
|
||||
return (a+b);
|
||||
}
|
||||
|
||||
//sub.c
|
||||
int sub(int a, int b){
|
||||
return (a-b);
|
||||
}
|
||||
|
||||
//mult.c
|
||||
int mult(int a, int b){
|
||||
return (a*b);
|
||||
}
|
||||
|
||||
//divi.c
|
||||
int divi(int a, int b){
|
||||
return (a/b);
|
||||
}
|
||||
```
|
||||
|
||||
Now generate object files `add.o`, `sub.o`, `mult.o`, and `divi.o` using GCC:
|
||||
|
||||
```
|
||||
$ gcc -c add.c sub.c mult.c divi.c
|
||||
```
|
||||
|
||||
The `-c` option skips the linking step and creates only object files.
|
||||
|
||||
Create a static library called `libmymath.a`, then remove the object files, as they're no longer required. (Note that using a `trash` [command][4] is safer than `rm`.)
|
||||
|
||||
```
|
||||
$ ar rs libmymath.a add.o sub.o mult.o divi.o
|
||||
$ trash *.o
|
||||
$ ls
|
||||
add.c divi.c libmymath.a mult.c mymath.h sub.c
|
||||
```
|
||||
|
||||
You have now created a simple example math library called `libmymath`, which you can use in C code. There are, of course, very complex C libraries out there, and this is the process their developers use to generate the final product that you and I install for use in C code.
|
||||
|
||||
Next, use your math library in some custom code and then link it.
|
||||
|
||||
### Create a statically linked application
|
||||
|
||||
Suppose you've written a command for mathematics. Create a file called `mathDemo.c` and paste this code into it:
|
||||
|
||||
```
|
||||
#include <mymath.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
int x, y;
|
||||
printf("Enter two numbers\n");
|
||||
scanf("%d%d",&x,&y);
|
||||
|
||||
printf("\n%d + %d = %d", x, y, add(x, y));
|
||||
printf("\n%d - %d = %d", x, y, sub(x, y));
|
||||
printf("\n%d * %d = %d", x, y, mult(x, y));
|
||||
|
||||
if(y==0){
|
||||
printf("\nDenominator is zero so can't perform division\n");
|
||||
exit(0);
|
||||
}else{
|
||||
printf("\n%d / %d = %d\n", x, y, divi(x, y));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Notice that the first line is an `include` statement referencing, by name, your own `libmymath` library.
|
||||
|
||||
Create an object file called `mathDemo.o` for `mathDemo.c` :
|
||||
|
||||
```
|
||||
$ gcc -I . -c mathDemo.c
|
||||
```
|
||||
|
||||
The `-I` option tells GCC to search for header files listed after it. In this case, you're specifying the current directory, represented by a single dot (`.` ).
|
||||
|
||||
Link `mathDemo.o` with `libmymath.a` to create the final executable. There are two ways to express this to GCC.
|
||||
|
||||
You can point to the files:
|
||||
|
||||
```
|
||||
$ gcc -static -o mathDemo mathDemo.o libmymath.a
|
||||
```
|
||||
|
||||
Alternately, you can specify the library path along with the library name:
|
||||
|
||||
```
|
||||
$ gcc -static -o mathDemo -L . mathDemo.o -lmymath
|
||||
```
|
||||
|
||||
In the latter example, the `-lmymath` option tells the linker to link the object files present in the `libmymath.a` with the object file `mathDemo.o` to create the final executable. The `-L` option directs the linker to look for libraries in the following argument (similar to what you would do with `-I` ).
|
||||
|
||||
### Analyzing the result
|
||||
|
||||
Confirm that it's statically linked using the `file` command:
|
||||
|
||||
```
|
||||
$ file mathDemo
|
||||
mathDemo: ELF 64-bit LSB executable, x86-64...
|
||||
statically linked, with debug_info, not stripped
|
||||
```
|
||||
|
||||
Using the `ldd` command, you can see that the executable is not dynamically linked:
|
||||
|
||||
```
|
||||
$ ldd ./mathDemo
|
||||
not a dynamic executable
|
||||
```
|
||||
|
||||
You can also check the size of the `mathDemo` executable:
|
||||
|
||||
```
|
||||
$ du -h ./mathDemo
|
||||
932K ./mathDemo
|
||||
```
|
||||
|
||||
In the example from my [previous article][5], the dynamic executable took up just 24K.
|
||||
|
||||
Run the command to see it work:
|
||||
|
||||
```
|
||||
$ ./mathDemo
|
||||
Enter two numbers
|
||||
10
|
||||
5
|
||||
|
||||
10 + 5 = 15
|
||||
10 - 5 = 5
|
||||
10 * 5 = 50
|
||||
10 / 5 = 2
|
||||
```
|
||||
|
||||
Looks good!
|
||||
|
||||
### When to use static linking
|
||||
|
||||
Dynamically linked executables are generally preferred over statically linked executables because dynamic linking keeps an application's components modular. Should a library receive a critical security update, it can be easily patched because it exists outside of the applications that use it.
|
||||
|
||||
When you use static linking, a library's code gets "hidden" within the executable you create, meaning the only way to patch it is to re-compile and re-release a new executable every time a library gets an update—and you have better things to do with your time, trust me.
|
||||
|
||||
However, static linking is a reasonable option if the code of a library exists either in the same code base as the executable using it or in specialized embedded devices that are expected to receive no updates.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/22/6/static-linking-linux
|
||||
|
||||
作者:[Jayashree Huttanagoudar][a]
|
||||
选题:[lkxed][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/jayashree-huttanagoudar
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://opensource.com/sites/default/files/lead-images/lenovo-thinkpad-laptop-concentration-focus-windows-office.png
|
||||
[2]: https://creativecommons.org/licenses/by/3.0/us/
|
||||
[3]: https://opensource.com/article/22/5/dynamic-linking-modular-libraries-linux
|
||||
[4]: https://www.redhat.com/sysadmin/recover-file-deletion-linux
|
||||
[5]: https://opensource.com/article/22/5/dynamic-linking-modular-libraries-linux
|
217
translated/tech/20220603 How static linking works on Linux.md
Normal file
217
translated/tech/20220603 How static linking works on Linux.md
Normal file
@ -0,0 +1,217 @@
|
||||
[#]: subject: "How static linking works on Linux"
|
||||
[#]: via: "https://opensource.com/article/22/6/static-linking-linux"
|
||||
[#]: author: "Jayashree Huttanagoudar https://opensource.com/users/jayashree-huttanagoudar"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: "robsean"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
如何在 Linux 上静态链接
|
||||
======
|
||||
学习如何将多个 C <ruby>对象<rt>object</rt></ruby> 文件组合到一个带有静态库的单个可执行文件文件之中。
|
||||
|
||||
![Woman using laptop concentrating][1]
|
||||
|
||||
图片作者:Mapbox Uncharted ERG, [CC-BY 3.0 US][2]
|
||||
|
||||
使用 C 编写的应用程序代码通常有多个源代码文件,但是,你需要将它们最终编译到一个单个的可执行文件。
|
||||
|
||||
你可以通过两种方式来完成这项工作:通过创建一个 <ruby>静态<rt>static</rt></ruby> 库 或 一个 <ruby>动态<rt>dynamic</rt></ruby> 库 (也被称为 <ruby>共享<rt>shared</rt></ruby> 库)。这两种类型的库在从它们是如何创建和链接的角度来看是不同的。你选择使用哪种方式取决于你的的具体使用情况。
|
||||
|
||||
在 [上一篇文章][3] 中,我演示了如何创建一个动态链接的可执行文件,这是一种更常用的方法。在这篇文章中,我将解释如何创建一个静态链接的可执行文件。
|
||||
|
||||
### 链接器使用静态库
|
||||
|
||||
链接器是一个命令,它将一个程序的数个部分组合到一起,并为它们重新组织存储器分配。
|
||||
|
||||
链接器的功能包括:
|
||||
|
||||
* 集成一个程序的所有的部分
|
||||
* 计算组织出一个新的存储器结构,以便所有的部分组合在一起
|
||||
* 重新复活存储器地址,以便程序可以在新的存储器组织下运行
|
||||
* 解析符号引用
|
||||
|
||||
作为这些链接器功能的结果,创建了一个名称为可执行文件的一个可运行程序。
|
||||
|
||||
静态库是通过复制一个程序中的所有必须的库模块到最终的可执行镜像来创建的。链接器将链接静态库作为编译过程的最后一步。可执行文件是通过解析外部引用、库实例程序与程序代码组合来创建的。
|
||||
|
||||
### 创建对象文件
|
||||
|
||||
这里是一个静态库的示例,以及其链接过程。首先,创建带有这些函数识别标志的头文件 `mymath.h` :
|
||||
|
||||
```
|
||||
int add(int a, int b);
|
||||
int sub(int a, int b);
|
||||
int mult(int a, int b);
|
||||
int divi(int a, int b);
|
||||
```
|
||||
|
||||
使用这些函数定义来创建 `add.c` 、`sub.c` 、`mult.c` 和 `divi.c` 文件:
|
||||
|
||||
```
|
||||
// add.c
|
||||
int add(int a, int b){
|
||||
return (a+b);
|
||||
}
|
||||
|
||||
//sub.c
|
||||
int sub(int a, int b){
|
||||
return (a-b);
|
||||
}
|
||||
|
||||
//mult.c
|
||||
int mult(int a, int b){
|
||||
return (a*b);
|
||||
}
|
||||
|
||||
//divi.c
|
||||
int divi(int a, int b){
|
||||
return (a/b);
|
||||
}
|
||||
```
|
||||
|
||||
现在,使用 GCC 来参加对象文件 `add.o` 、`sub.o` 、`mult.o` 和 `divi.o` :
|
||||
|
||||
```
|
||||
$ gcc -c add.c sub.c mult.c divi.c
|
||||
```
|
||||
|
||||
`-c` 选项跳过链接步骤,并且只创建对象文件。
|
||||
|
||||
创建一个名称为 `libmymath.a` 的静态库,接下来,移除对象文件,因为它们不再被需要。(注意,使用一个 `trash` 命令比使用一个 `rm` 命令更安全。)
|
||||
|
||||
```
|
||||
$ ar rs libmymath.a add.o sub.o mult.o divi.o
|
||||
$ trash *.o
|
||||
$ ls
|
||||
add.c divi.c libmymath.a mult.c mymath.h sub.c
|
||||
```
|
||||
|
||||
现在,你已经创建了一个简单的名称为 `libmymath` 是示例数学库,你可以在 C 代码中使用它。当然,这里有非常复杂的 C 库,这就是他们这些开发者来生成最终产品的工艺流程,你和我可以安装这些库并在 C 代码中使用。
|
||||
|
||||
接下来,在一些自定义代码中使用你的数学库,然后链接它。
|
||||
|
||||
### 创建一个静态链接的应用程序
|
||||
|
||||
假设你已经为数学运算编写了一个命令。创建一个名称为 `mathDemo.c` 的文件,并将这些代码复制粘贴至其中:
|
||||
|
||||
```
|
||||
#include <mymath.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
int x, y;
|
||||
printf("Enter two numbers\n");
|
||||
scanf("%d%d",&x,&y);
|
||||
|
||||
printf("\n%d + %d = %d", x, y, add(x, y));
|
||||
printf("\n%d - %d = %d", x, y, sub(x, y));
|
||||
printf("\n%d * %d = %d", x, y, mult(x, y));
|
||||
|
||||
if(y==0){
|
||||
printf("\nDenominator is zero so can't perform division\n");
|
||||
exit(0);
|
||||
}else{
|
||||
printf("\n%d / %d = %d\n", x, y, divi(x, y));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
注意:第一行是一个 `include` 语句,通过名称来引用你自己的 `libmymath` 库。
|
||||
|
||||
针对 `mathDemo.c` 创建一个名称为 `mathDemo.o` 的对象文件:
|
||||
|
||||
```
|
||||
$ gcc -I . -c mathDemo.c
|
||||
```
|
||||
|
||||
`-I` 选项告诉 GCC 来搜索在其后列出的头文件。在这个实例中,你正在具体指定当前目录,通过一个单个点 (`.` ) 来表示。
|
||||
|
||||
Link `mathDemo.o` with `libmymath.a` 来参加最终的可执行文件。这里有两种方法来向 GCC 表达这一点。
|
||||
|
||||
你可以指向文件:
|
||||
|
||||
```
|
||||
$ gcc -static -o mathDemo mathDemo.o libmymath.a
|
||||
```
|
||||
|
||||
或者,你可以具体指定库的路径和库的名称:
|
||||
|
||||
```
|
||||
$ gcc -static -o mathDemo -L . mathDemo.o -lmymath
|
||||
```
|
||||
|
||||
在后面的那个示例中,`-lmymath` 选项告诉链接器来链接随对象文件 `mathDemo.o` 出现的对象文件 `libmymath.a` 来创建最终的可执行文件。`-L` 选项指示链接器在下面的参数中查找库 (类似于你使用 `-I` 所做的工作)。
|
||||
|
||||
### 分析结果
|
||||
|
||||
使用 `file` 命令来确认它是静态链接的:
|
||||
|
||||
```
|
||||
$ file mathDemo
|
||||
mathDemo: ELF 64-bit LSB executable, x86-64...
|
||||
statically linked, with debug_info, not stripped
|
||||
```
|
||||
|
||||
使用 `ldd` 命令,你将会看到该可执行文件不是动态链接的:
|
||||
|
||||
```
|
||||
$ ldd ./mathDemo
|
||||
not a dynamic executable
|
||||
```
|
||||
|
||||
你也可以检查 `mathDemo` 可执行文件的大小:
|
||||
|
||||
```
|
||||
$ du -h ./mathDemo
|
||||
932K ./mathDemo
|
||||
```
|
||||
|
||||
在我 [前一篇文章][5] 的示例中,动态链接的可执行文件只占有 24K 大小。
|
||||
|
||||
运行该命令来看看它的工作内容:
|
||||
|
||||
```
|
||||
$ ./mathDemo
|
||||
Enter two numbers
|
||||
10
|
||||
5
|
||||
|
||||
10 + 5 = 15
|
||||
10 - 5 = 5
|
||||
10 * 5 = 50
|
||||
10 / 5 = 2
|
||||
```
|
||||
|
||||
看起来令人满意!
|
||||
|
||||
### 何时使用静态链接
|
||||
|
||||
动态链接可执行文件通常优于静态链接可执行文件,因为动态链接会保持应用程序的组件模块化。假如一个库接收到一次关键安全更新,那么它可以很容易地修补,因为它存在于应用程序的外部。
|
||||
|
||||
当你使用静态链接时,库的代码会 "隐藏" 在你创建的可执行文件之中,意味着在库每次更新时(相信我,你会有更好的东西),仅有的一种修补它的方法是重新编译和重新发布一个新的可执行文件。
|
||||
|
||||
不过,如果一个库的代码,要么存在于它正在使用的具有相同代码的可执行文件中,要么存在于专用的预期不会接收到任何更新的嵌入式设备中,那么静态连接将是一种可接受的选项。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/22/6/static-linking-linux
|
||||
|
||||
作者:[Jayashree Huttanagoudar][a]
|
||||
选题:[lkxed][b]
|
||||
译者:[robsean](https://github.com/robsean)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/jayashree-huttanagoudar
|
||||
[b]: https://github.com/lkxed
|
||||
[1]: https://opensource.com/sites/default/files/lead-images/lenovo-thinkpad-laptop-concentration-focus-windows-office.png
|
||||
[2]: https://creativecommons.org/licenses/by/3.0/us/
|
||||
[3]: https://opensource.com/article/22/5/dynamic-linking-modular-libraries-linux
|
||||
[4]: https://www.redhat.com/sysadmin/recover-file-deletion-linux
|
||||
[5]: https://opensource.com/article/22/5/dynamic-linking-modular-libraries-linux
|
Loading…
Reference in New Issue
Block a user