计算机组成原理(六):动态链接

news2024/12/17 0:53:10

动态链接(Dynamic Linking)是现代计算机操作系统和程序运行中一种重要的机制,它允许程序在运行时将所需的库或模块加载到内存中,而不是在编译时将其嵌入到可执行文件中。这样可以有效节省内存空间,并使程序的维护和升级更加灵活。

概念

静态链接 vs 动态链接

  • 静态链接(Static Linking):程序在编译阶段将所有依赖的库代码嵌入到可执行文件中,生成独立的可执行程序。优点是运行时不需要依赖外部库,缺点是文件体积较大,难以维护。
  • 动态链接(Dynamic Linking):程序运行时,将库文件动态加载到内存中,并将其与可执行文件进行链接。动态库(如 .dll.so 文件)独立于程序文件存在,多个程序可以共享相同的动态库。

动态链接库(Dynamic Link Library)

  • 动态库是操作系统提供的共享库,存储公共函数或资源。例如:
    • Windows 系统使用 .dll 文件。
    • Linux/Unix 系统使用 .so 文件(Shared Object)。
  • 动态库的共享性使得更新库文件时无需重新编译和发布所有依赖该库的程序。

工作原理

程序加载

  • 当用户启动一个程序时,操作系统的加载器(Loader)负责将程序的代码段和数据段加载到内存。
  • 加载器同时会识别程序依赖的动态库,并将其加载到内存中。

符号解析

  • 在动态链接过程中,动态链接器(Dynamic Linker)负责将程序中对外部函数或变量的引用解析到动态库中对应的实际地址。
  • 动态链接器通过符号表(Symbol Table)和重定位表(Relocation Table)完成符号绑定和地址重定向。

延迟绑定(Lazy Binding)

  • 为了提升程序启动速度,动态链接器可以采用延迟绑定机制,在程序运行到需要使用动态库的函数或变量时,才完成实际的地址解析。
  • 延迟绑定减少了启动时的开销,但可能导致首次调用某些函数时有额外的延迟。

特点

优点

  1. 节省存储空间:多个程序共享相同的动态库,避免了代码冗余。
  2. 方便维护:更新动态库时,无需修改或重新编译依赖的程序。
  3. 支持模块化设计:程序可以动态加载功能模块,增强灵活性。
  4. 运行时功能扩展:支持插件机制,可以在运行时添加新功能。

缺点

  1. 运行时开销:符号解析和地址绑定会增加运行时的开销,尤其是使用延迟绑定时。
  2. 依赖问题:如果动态库被删除、损坏或更新不兼容,程序可能无法正常运行(即“依赖地狱”问题)。
  3. 调试复杂性:动态链接的符号解析和加载过程可能增加程序调试的难度。

应用

操作系统中的共享库

  • 动态链接最常见的应用是操作系统提供的共享库(如标准 C 库 libc、图形库、设备驱动等)。
  • 多个程序可以同时调用同一个动态库,而不需要为每个程序单独复制库代码。
  • 示例:
    • Linux 系统中:libc.so 提供标准输入/输出、文件操作等基本功能。
    • Windows 系统中:kernel32.dll 提供底层操作系统服务。

插件机制

  • 应用程序可以通过动态链接加载插件,动态扩展功能。
  • 示例:
    • 浏览器插件(如 Chrome 的扩展程序)通过动态链接库扩展功能。
    • 游戏引擎(如 Unity、Unreal Engine)支持通过动态加载模块来添加新关卡或特性。

模块化设计

  • 动态链接允许大型软件按模块划分功能,各模块独立开发并动态加载。
  • 示例:
    • 数据库系统(如 MySQL)的存储引擎通过动态库实现,如 InnoDB 引擎。
    • 科学计算软件动态加载特定功能模块(如数学运算库、图形渲染库)。

系统更新和补丁

  • 软件更新或安全补丁通常通过替换动态库实现,而不需要重新分发整个程序。
  • 示例:
    • 操作系统安全补丁更新动态库,修复漏洞。
    • 大型软件(如 Photoshop)升级特定功能库,而无需替换完整程序。

示例

动态链接库的创建与使用

1. 创建动态库

  • 创建一个动态库文件,包含一些可供外部调用的函数。

mylib.h

#ifndef MYLIB_H
#define MYLIB_H

// 导出符号(跨平台兼容)
#ifdef _WIN32
#define MYLIB_EXPORT __declspec(dllexport)
#else
#define MYLIB_EXPORT
#endif

extern "C" {
    MYLIB_EXPORT int add(int a, int b);
    MYLIB_EXPORT int multiply(int a, int b);
}

#endif

mylib.cpp

#include "mylib.h"

int add(int a, int b) {
    return a + b;
}

int multiply(int a, int b) {
    return a * b;
}

编译动态库

  • Linux:

    g++ -shared -fPIC -o libmylib.so mylib.cpp
    
  • Windows(使用 MinGW 或 Visual Studio):

    g++ -shared -o mylib.dll mylib.cpp
    

2. 使用动态库

创建一个依赖动态库的主程序。

main.cpp

#include <iostream>
#include "mylib.h"  // 包含动态库头文件

int main() {
    int a = 5, b = 3;

    std::cout << "Addition: " << add(a, b) << std::endl;
    std::cout << "Multiplication: " << multiply(a, b) << std::endl;

    return 0;
}

编译程序

  • Linux:

    g++ -o main main.cpp -L. -lmylib
    
    • -L. 指定动态库路径(当前目录)。
    • -lmylib 链接动态库 libmylib.so
  • Windows(MinGW):

    g++ -o main.exe main.cpp -L. -lmylib
    

调试动态链接程序

动态链接程序运行时可能遇到符号解析失败或库加载错误等问题。以下是调试的常见方法。

1.查看动态库依赖

  • Linux:使用 ldd 查看程序的动态库依赖。
ldd main

示例输出:

linux-vdso.so.1 (0x00007ffcddffd000)
libmylib.so => ./libmylib.so (0x00007f2a4b7a1000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f2a4b3c9000)
/lib64/ld-linux-x86-64.so.2 (0x00007f2a4b9a3000)
  • Windows:使用 Dependency Walker 工具检查 .dll 依赖。

2.设置库路径

  • 动态库路径未正确设置可能导致加载失败。
    • Linux :使用环境变量 LD_LIBRARY_PATH 指定库路径:
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
./main
  • Windows:将 .dll 文件放置在可执行程序同一目录下,或者配置系统环境变量 PATH

3.使用调试工具

  • Linux:使用 gdb 调试运行时动态链接。

    gdb ./main
    

    在 gdb 中运行程序:

    (gdb) run
    

    如果出现动态库加载错误,可以使用 info sharedlibrary 查看已加载的共享库。

  • Windows:使用 Visual Studio 或 MinGW 的 gdb 进行类似操作。

4.动态库符号调试

  • 确保动态库在编译时包含调试信息:

    g++ -shared -fPIC -g -o libmylib.so mylib.cpp
    

    使用 gdb 时,可以查看动态库中的函数是否正确加载:

    (gdb) info functions
    

5. 手动加载动态库

动态链接库支持在运行时手动加载库文件(延迟绑定)。

代码:使用 dlopendlsym(Linux)

#include <iostream>
#include <dlfcn.h>  // 动态加载相关函数

int main() {
    void* handle = dlopen("./libmylib.so", RTLD_LAZY);
    if (!handle) {
        std::cerr << "Cannot load library: " << dlerror() << std::endl;
        return 1;
    }

    // 加载函数指针
    typedef int (*Operation)(int, int);
    Operation add = (Operation)dlsym(handle, "add");
    Operation multiply = (Operation)dlsym(handle, "multiply");

    if (!add || !multiply) {
        std::cerr << "Cannot load symbol: " << dlerror() << std::endl;
        dlclose(handle);
        return 1;
    }

    // 调用函数
    std::cout << "Addition: " << add(5, 3) << std::endl;
    std::cout << "Multiplication: " << multiply(5, 3) << std::endl;

    // 关闭动态库
    dlclose(handle);
    return 0;
}

常见问题

动态库加载失败

  • 问题:
    • 找不到库文件,错误:error while loading shared libraries
  • 解决:
    • 确认库路径是否正确。
    • 在 Linux 中设置 LD_LIBRARY_PATH,或编辑 /etc/ld.so.conf 并运行 ldconfig

符号解析失败

  • 问题:
    • 程序运行时报 undefined symbol 错误。
  • 解决:
    • 检查动态库是否正确导出了符号。
    • 确保函数声明使用了 extern "C"(避免 C++ 名称修饰)。

版本不兼容

  • 问题:
    • 不同版本的动态库可能引起 API 或 ABI(Application Binary Interface)不兼容。
  • 解决:
    • 在程序中检查库版本,使用正确的库文件。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2260773.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python | 数据可视化中常见的4种标注及示例

在Python的数据可视化中&#xff0c;标注&#xff08;Annotation&#xff09;技术是一种非常有用的工具&#xff0c;它可以帮助用户更准确地解释图表中的数据和模式。在本文中&#xff0c;将带您了解使用Python实现数据可视化时应该了解的4种标注。 常见的标注方式 文本标注箭…

【原生js案例】如何实现一个穿透字体颜色的导航

普通的导航大家都会做&#xff0c;像这种穿透字体的导航应该很少见吧。高亮不是通过单独设置一个active类来设置字体高亮颜色&#xff0c;鼠标滑过导航项&#xff0c;字体可以部分是黑色&#xff0c;不分是白色&#xff0c;这种效果的实现 感兴趣的可以关注下我的系列课程【we…

前端中图标的使用

1 antd 使用inconfont.cn中的图标 <template><div class"icons-list"><icon-font type"icon-tuichu" /><icon-font type"icon-facebook" /><icon-font type"icon-twitter" /></div> </templ…

回归预测 | MATLAB实现CNN-BiGRU卷积神经网络结合双向门控循环单元多输入单输出回归预测

回归预测 | MATLAB实现CNN-BiGRU卷积神经网络结合双向门控循环单元多输入单输出回归预测 目录 回归预测 | MATLAB实现CNN-BiGRU卷积神经网络结合双向门控循环单元多输入单输出回归预测预测效果基本介绍程序设计参考资料预测效果 基本介绍 CNN-BiGRU,即卷积神经网络(CNN)与双…

医学分割数据集B超图片肝脏分割数据集labelme格式271张1类别

数据集格式&#xff1a;labelme格式(不包含mask文件&#xff0c;仅仅包含jpg图片和对应的json文件) 图片数量(jpg文件个数)&#xff1a;271 标注数量(json文件个数)&#xff1a;271 标注类别数&#xff1a;1 标注类别名称:["liver"] 每个类别标注的框数&#xf…

【目标检查】YOLO系列之:Triton 推理服务器Ultralytics YOLO11

Triton 推理服务器 1、引言2、Triton服务器2.1 什么是Triton Inference Server2.2 将YOLO11 导出为ONNX 格式2.3 设置Triton 模型库2.3.1 创建目录结构2.3.2 将导出的ONNX 模型移至Triton 资源库 2.4 运行Triton 推断服务器2.4.1 使用 Docker 运行Triton Inference Server2.4.2…

论文学习——多种变化环境下基于多种群进化的动态约束多目标优化

论文题目&#xff1a;Multipopulation Evolution-Based Dynamic Constrained Multiobjective Optimization Under Diverse Changing Environments 多种变化环境下基于多种群进化的动态约束多目标优化&#xff08;Qingda Chen , Member, IEEE, Jinliang Ding , Senior Member, …

【C++】判断能否被 3, 5, 7 整除问题解析与优化

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;题目描述&#x1f4af;老师代码实现与分析老师代码逻辑分析优点缺点 &#x1f4af;学生代码实现与分析学生代码逻辑分析优点缺点 &#x1f4af;改进与优化优化代码实现优化…

【构建工具】现代开发的重要角色

你可能有所听闻构建工具&#xff0c;但是不知道是干什么的&#xff0c;或者是开发中用到了&#xff0c;大概会使用&#xff0c;但是想理解一下具体的工作原理等&#xff0c;那么我将分享一下我对其的理解。【 我将分为两篇来讲解】。 当我们谈到构建工具时&#xff0c;可以把它…

npm或yarn包配置地址源

三种方法 1.配置.npmrc 文件 在更目录新增.npmrc文件 然后写入需要访问的包的地址 2.直接yarn.lock文件里面修改地址 简单粗暴 3.yarn install 的时候添加参数 设置包的仓库地址 yarn config set registry https://registry.yarnpkg.com 安装&#xff1a;yarn install 注意…

Unity集成Wwise并进行开发

1. 背景 项目要接入WWise&#xff0c;学习一下 1.1 与Unity自带音频系统的区别 Unity有自己的原生音乐功能&#xff1a;AduioSound。但是这个功能较为简单&#xff0c;对于音效开发人员来说并不是很友好。在一些大型的游戏中&#xff0c;音效会接入Wwise这个软件。音效开发者…

【AI知识】有监督学习之回归任务(附线性回归代码及可视化)

1. 回归的基本概念 在机器学习的有监督学习中&#xff0c;回归&#xff08;Regression&#xff09;是一种常见的任务&#xff0c;它的目标是通过观察数据来建立一个模型&#xff0c;用一个或多个自变量来预测因变量的值。 回归分析通常用于&#xff1a; a.预测&#xff0c;基于…

C语言专题之宏的基本概念

合理使用宏可以使我们的代码更加简单&#xff0c;接下来小编就来讲解宏的基本概念&#xff01; 一、宏的定义 宏定义是C/C语言中一项强大而灵活的特性&#xff0c;它允许程序员使用预处理器指令来创建简化的代码表示。这种机制不仅提高了代码的可读性和可维护性&#xff0c;还…

MySQL 复合查询(重点)

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 MySQL 复合查询&#xff08;重点&#xff09; 收录于专栏[MySQL] 本专栏旨在分享学习MySQL的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; …

WPF 控件

<div id"content_views" class"htmledit_views"><p id"main-toc"><strong>目录</strong></p> WPF基础控件 按钮控件&#xff1a; Button:按钮 RepeatButton:长按按钮 RadioButton:单选按钮 数据显示控件 Te…

Docker方式安装人人影视离线完整安装包

本文软件由网友 ルリデ 推荐&#xff1b; 上周&#xff0c;人人影视创始人宣布将人人影视二十年字幕数据开源分享 目前提供了两种使用方式&#xff1a; “在线应用” &#xff1a;意味着需要有互联网才可以使用。官方提供了网站&#xff1a;https://yyets.click “离线使用” …

opencv——(图像梯度处理、图像边缘化检测、图像轮廓查找和绘制、透视变换、举例轮廓的外接边界框)

一、图像梯度处理 1 图像边缘提取 cv2.filter2D(src, ddepth, kernel[, dst[, anchor[, delta[, borderType]]]]) 功能&#xff1a;用于对图像进行卷积操作。卷积是图像处理中的一个基本操作&#xff0c;它通过一个称为卷积核&#xff08;或滤波器&#xff09;的小矩阵在图像上…

物联网安全-ARMv8-M Trustzone 实操

前言 本文针对ARMv8m架构M23/M33 MCU安全特性使用进行介绍,以nxp LPC55xx系列和STM32L5xx系列为例,为大家阐述如何使用Trustzone技术提高物联网设备安全性,适合有一定平台安全基础的物联网设备开发人员、安全方案开发人员。 背景 为了提升平台安全性,ARM推出了ARMv8m架构…

深入理解偏向锁、轻量级锁、重量级锁

一、对象结构和锁状态 synchronized关键字是java中的内置锁实现&#xff0c;内置锁实际上就是个任意对象&#xff0c;其内存结构如下图所示 其中&#xff0c;Mark Word字段在64位虚拟机下占64bit长度&#xff0c;其结构如下所示 可以看到Mark Word字段有个很重要的作用就是记录…

《拉依达的嵌入式\驱动面试宝典》—C/CPP基础篇(五)

《拉依达的嵌入式\驱动面试宝典》—C/CPP基础篇(五) 你好,我是拉依达。 感谢所有阅读关注我的同学支持,目前博客累计阅读 27w,关注1.5w人。其中博客《最全Linux驱动开发全流程详细解析(持续更新)-CSDN博客》已经是 Linux驱动 相关内容搜索的推荐首位,感谢大家支持。 《拉…