The differences of dynamically link and static link linux so

本文介绍了Linux环境下静态库与动态库的区别,重点讲解了动态链接的工作原理及其过程,并探讨了动态加载的特点与API。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

提起Dynamically linked,则要归结到库的概念和应用了,所以我就系统地了解了一下子,并愿意贴出来,跟大家一起分享。

库的目的是将类似的功能封装在一个单元集中。这些单元可以被其他开发人员共享,并称其为模块化编程,也就是说从模块中编译程序。Linux支持两种类型的库,每种都有自己的优点和缺点。静态库在编译程序时,将库中相应的功能绑定到程序中;然而动态库则不同,它是当程序在运行时才被加载的。图1显示了linux库的层次结构。

图1 linux库的层次结构

你可以通过两种方式来使用共享库的:要么在程序运行时动态地链接,要么在用户的控制下进行动态地加载。这篇文章将讨论着两种方式。

静态库对于功能少的小程序中是有益的。然而对于需要多个库的程序来说,共享库则可以减少程序的内存占用(包括磁盘上的和运行时的内存)。这是因为多个程序可以同时使用一个共享库,因此在一个时间,内存中只需要保留一个共享库的副本即可。使用静态库,每一个正在运行的程序库都有个库的副本。

GNU / Linux提供两种方法来处理共享库(每个方法都是Sun Solaris起源)。你可以动态链接共享库,并在执行时,使用Linux系统加载库(除非它已经在内存中了)。另一种方案是有选择性地调用进程中的库函数,被称为动态加载。采用动态加载,程序可以加载一个特定的库(除非已经加载),然后调用该库中的某一特定功能。 (图2显示了这两种方法。)这是在建立支持插件的应用程序时所共同使用的模式。

图2 动态链接

Linux的动态链接

现在,让我们深入探讨了在Linux中使用动态链接的共享库的过程。当用户启动应用程序时,它们是调用一个可执行的和链接格式(ELF)的镜像。内核始于加载ELF映像到用户空间的虚拟内存的过程。内核注意到一个名为ELF段,被称为.interp,这表明动态链接器要被使用(/lib/ld-linux.so),如清单1所示。这类似于在UNIX中所解释定义的脚本文件(#!/bin/sh):只是在不同的上下文中使用。

注意:ld-linux.so(elf动态库的装载器)

清单1 使用只readelf命令来展示程序的头文件

mtj@camus:~/dl$ readelf -l dl

Elf file type is EXEC (Executable file)

  Entry point 0x8048618

  There are 7 program headers, starting at offset 52

  Program Headers:

  Type           Offset   VirtAddr    PhysAddr   FileSiz MemSiz  Flg Align

  PHDR           0x000034 0x08048034 0x08048034  0x000e0 0x000e0 R E 0x4

  INTERP         0x000114 0x08048114 0x08048114 0x00013  0x00013 R   0x1

  [Requesting program interpreter: /lib/ld-linux.so.2]

  LOAD           0x000000 0x08048000 0x08048000 0x00958  0x00958 R E 0x1000

  LOAD           0x000958 0x08049958 0x08049958  0x00120 0x00128 RW  0x1000

  DYNAMIC        0x00096c 0x0804996c  0x0804996c 0x000d0 0x000d0 RW  0x4

  NOTE           0x000128 0x08048128 0x08048128  0x00020 0x00020 R   0x4

  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000  0x00000 RW  0x4

  ...

  mtj@camus:~dl$

请注意,ld-linux.so本身就是一个ELF共享库,但它是静态编译的,并不依赖于共享库。当需要动态链接时,内核自动启动动态链接器(ELF解释器),它先初始化自身,然后加载指定的共享对象(除非已加载)。之后,它执行必要的再定位,包括目标共享对象所使用的共享对象。 LD_LIBRARY_PATH环境变量定义了可用的共享对象的路径。完成后,控制权转移回原来的程序,开始执行。 

Linxu中的动态加载

其实Linux会为给定的程序自动装载和链接库,它可以分享这个应用程序本身的控制。在这种情况下,这一过程被称为动态加载。有了动态加载,应用程序可以指定一个特定的库来加载,然后将其作为一个可执行库来使用(即调用其中的函数)。然而,正如你前边所学,共享库动态加载功能,只不过是一个标准的共享库(ELF共享对象)。事实上,ld-linux动态链接作为ELF加载器和解释器仍然参与了这项工作的过程。 
动态加载(DL)的API可以动态加载共享库,并允许将其提供给用户空间的程序。API虽然小,但是它提供程序需要的所有东西,并在程序执行背后做了好多工作,完整的API见表1。

表1 完整的API


Function

Description

dlopen

打开一个动态链接库

dlsym

获取所打开文件对象的描述符地址

dlerror

返回最后一次发生错误的信息字符串

dlclose

Closes an object file关闭一个文件对象











### C++ Project Module Linking In a C++ project, ensuring proper linkage between various modules is crucial for successful compilation and execution of the program. Modules here refer to separate source files or libraries that need to interact with each other. #### Understanding Compilation Units Each `.cpp` file constitutes an independent compilation unit which gets compiled into object code separately before being linked together during the final build phase[^1]. This separation allows developers to manage large projects more efficiently by dividing functionality across multiple smaller units. #### Using Header Files (.h/.hpp) Header files play a vital role in defining interfaces used within these modules. They contain declarations such as function prototypes, class definitions, macros, etc., necessary for inter-module communication without exposing implementation details. Including relevant headers at the beginning of your cpp files ensures all required symbols are available when compiling individual parts of the application. ```cpp // Example header inclusion #include "moduleA.h" ``` #### Static Libraries vs Dynamic Libraries For linking purposes, two types of library configurations exist: - **Static Library**: Compiled directly into executables resulting in larger binaries but faster runtime performance since there's no dependency lookup overhead. To create static libraries from several .o (object) files generated after preprocessing and assembling stages: ```bash ar rcs libstatic.a objfile1.o objfile2.o ... ``` - **Dynamic/Shared Library**: Loaded dynamically at run-time reducing executable size while allowing updates independently of applications using them provided ABI remains compatible. Creating shared objects involves specifying `-shared` flag along with position-independent code generation options like `-fPIC`. ```bash g++ -shared -o libdynamic.so *.o ``` When configuring builds through tools like CMake, prefer setting properties rather than hardcoding flags whenever possible due to differences among platforms and toolchains. #### Managing Dependencies Within Build Systems Modern build systems simplify managing dependencies automatically handling include paths, linker settings based on target specifications avoiding manual intervention prone errors. Using `target_link_libraries()` directive inside cmake scripts connects targets effectively abstracting away underlying complexities associated with platform-specific commands. ```cmake add_executable(myapp main.cpp) target_include_directories(myapp PRIVATE ${PROJECT_SOURCE_DIR}/include) target_link_libraries(myapp PRIVATE mylib) ``` This approach leverages abstraction layers offered by modern IDEs/build frameworks promoting portability across diverse environments. --related questions-- 1. What considerations should be taken into account when choosing between static and dynamic linking? 2. How does one resolve symbol conflicts arising from multiple versions of the same library present simultaneously? 3. Can you explain what happens behind the scenes during the linking process in detail? 4. In terms of best practices, how often should external dependencies be updated within ongoing development cycles?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值