Open-source News

How dynamic linking for modular libraries works on Linux

opensource.com - Tue, 05/31/2022 - 15:00
How dynamic linking for modular libraries works on Linux Jayashree Hutt… Tue, 05/31/2022 - 03:00 Register or Login to like Register or Login to like

When you write an application using the C programming language, your code usually has multiple source files.

Ultimately, these files must be compiled into a single executable. You can do this by creating either static or dynamic libraries (the latter are also referred to as shared libraries). These two types of libraries vary in how they are created and linked. Both have advantages and disadvantages, depending on your use case.

Dynamic linking is the most common method, especially on Linux systems. Dynamic linking keeps libraries modular, so just one library can be shared between any number of applications. Modularity also allows a shared library to be updated independently of the applications that rely upon it.

In this article, I demonstrate how dynamic linking works. In a future article, I'll demonstrate static linking.

Linker

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. Before you can create a dynamically linked executable, you need some libraries to link to and an application to compile. Get your favorite text editor ready and follow along.

Create the object files

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. I'm placing all of the code in one code block, so divide it up among four files, as indicated in the comments:

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

Programming and development Red Hat Developers Blog Programming cheat sheets Try for free: Red Hat Learning Subscription eBook: An introduction to programming with Bash Bash shell scripting cheat sheet eBook: Modernizing Enterprise Java Creating a shared object file

Dynamic libraries are linked during the execution of the final executable. Only the name of the dynamic library is placed in the final executable. The actual linking happens during runtime, when both executable and library are placed in the main memory.

In addition to being sharable, another advantage of a dynamic library is that it reduces the size of the final executable file. Instead of having a redundant copy of the library, an application using a library includes only the name of the library when the final executable is created.

You can create dynamic libraries from your existing sample code:

$ gcc -Wall -fPIC -c add.c sub.c mult.c divi.c

The option -fPIC tells GCC to generate position-independent code (PIC). The -Wall option isn't necessary and has nothing to do with how the code is compiling. Still, it's a valuable option because it enables compiler warnings, which can be helpful when troubleshooting.

Using GCC, create the shared library libmymath.so:

$ gcc -shared -o libmymath.so \
add.o sub.o mult.o divi.o

You have now created a simple example math library, libmymath.so, 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 or I install for use in C code.

Next, you can use your new math library in some custom code, then link it.

Creating a dynamically linked executable

Suppose you've written a command for mathematics. Create a file called mathDemo.c and paste this code into it:

#include
#include
#include

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. To use a shared library, you must have it installed. If you don't install the library you use, then when your executable runs and searches for the included library, it won't be able to find it. Should you need to compile code without installing a library to a known directory, there are ways to override default settings. For general use, however, it's expected that libraries exist in known locations, so that's what I'm demonstrating here.

Copy the file libmymath.so to a standard system directory, such as /usr/lib64, and then run ldconfig. The ldconfig command creates the required links and cache to the most recent shared libraries found in the standard library directories.

$ sudo cp libmymath.so /usr/lib64/
$ sudo ldconfigCompiling the application

Create an object file called mathDemo.o from your application source code (mathDemo.c):

$ gcc -I . -c mathDemo.c

The -I option tells GCC to search for header files (mymath.h in this case) in the directory listed after it. In this case, you're specifying the current directory, represented by a single dot (.). Create an executable, referring to your shared math library by name using the -l option:

$ gcc -o mathDynamic mathDemo.o -lmymath

GCC finds libmymath.so because it exists in a default system library directory. Use ldd to verify the shared libraries used:

$ ldd mathDemo
    linux-vdso.so.1 (0x00007fffe6a30000)
    libmymath.so => /usr/lib64/libmymath.so (0x00007fe4d4d33000)
    libc.so.6 => /lib64/libc.so.6 (0x00007fe4d4b29000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fe4d4d4e000)

Take a look at the size of the mathDemo executable:

$ du ./mathDynamic
24   ./mathDynamic

It's a small application, of course, and the amount of disk space it occupies reflects that. For comparison, a statically linked version of the same code (as you'll see in my next article) is 932K!

$ ./mathDynamic
Enter two numbers
25
5

25 + 5 = 30
25 - 5 = 20
25 * 5 = 125
25 / 5 = 5

You can verify that it's dynamically linked with the file command:

$ file ./mathDynamic
./mathDynamic: ELF 64-bit LSB executable, x86-64,
dynamically linked,
interpreter /lib64/ld-linux-x86-64.so.2,
with debug_info, not stripped

Success!

Dynamically linking

A shared library leads to a lightweight executable, as the linking happens during runtime. Because it resolves references during runtime, it does take more time for execution. However, since the vast majority of commands on everyday Linux systems are dynamically linked and on modern hardware, the time saved is negligible. Its inherent modularity is a powerful feature for developers and users alike.

In this article, I described how to create dynamic libraries and link them into a final executable. I'll use the same source code to create a statically linked executable in my next article.

Learn how to combine multiple C object files into single executable with dynamic libraries.

Image by:

Paul Lewin. Modified by Opensource.com. CC BY-SA 2.0

Programming Linux What to read next How to handle dynamic and static libraries in Linux Anyone can compile open source code in these three simple steps Dynamically linking libraries while compiling code This work is licensed under a Creative Commons Attribution-Share Alike 4.0 International License. Register or Login to post a comment.

Linux 5.19 Allows Using TRIM To Zero-Out Sectors On Supported eMMC

Phoronix - Tue, 05/31/2022 - 06:30
Last week the (e)MMC storage new feature code landed into the Linux 5.19 merge window...

NixOS 22.05 Released With New Graphical Installer

Phoronix - Tue, 05/31/2022 - 05:05
NixOS as the Linux distribution built around the unique Nix package manager is out with its first release of the year...

OpenJPH 0.9 Released For Further Speeding Up Open-Source High-Throughput JPEG 2000

Phoronix - Mon, 05/30/2022 - 19:36
While JPEG XL is regarded as the next-generation JPEG standard and JPEG 2000 never quite took off to supersede the original JPEG standard, there are open-source projects continuing to work on this image compression standard. OpenJPH 0.9 was released last week as the open-source high-throughput JPEG 2000 implementation and with this new version comes even more performance gains...

Raspberry Pi Sense HAT Joystick Driver Lands In Linux 5.19

Phoronix - Mon, 05/30/2022 - 19:02
This weekend Linus Torvalds landed the Raspberry Pi Sense HT Joystick driver into the Linux 5.19 kernel as part of the input subsystem updates...

OverlayFS Adding Support For IDMAPPED Layers For Various Benefits

Phoronix - Mon, 05/30/2022 - 17:46
Sent in this morning for the Linux 5.19 merge window were the OverlayFS updates of which the main feature addition this cycle is support for IDMAPPED layers...

LoongArch CPU Port Might Still Land For Linux 5.19

Phoronix - Mon, 05/30/2022 - 17:27
One of the open questions this merge window is whether the MIPS64-based LoongArch CPU architecture port of the kernel will manage to land for the Linux 5.19 cycle. There has been a discussion this holiday weekend by upstream kernel developers and looks like it may still land, but possibly without necessary hardware drivers included...

Pages