TranslateProject/sources/tech/20220603 How static linking works on Linux.md
2022-06-17 16:57:10 +08:00

7.3 KiB

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

Image by Mapbox Uncharted ERG, CC-BY 3.0 US

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, 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 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, 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 选题:lkxed 译者:译者ID 校对:校对者ID

本文由 LCTT 原创编译,Linux中国 荣誉推出