运行时链接

2023-11-12

基本概念

运行时链接,是在程序运行时(而非编译时或加载时)将程序代码与其依赖的库代码进行链接的过程。动态链接在程序启动时或实际运行过程中通过API函数完成。这种方式的主要优点是它允许程序在运行时加载和卸载不同的库模块,从而实现更高的模块化和灵活性。

在C语言的上下文中,运行时链接通常通过动态链接库(例如 .so 文件在Unix-like系统中,.dll 文件在Windows系统中)来实现。

以下是运行时链接的基本概念和步骤:

  1. 动态链接库:与静态库(如 .a.lib 文件)不同,动态链接库包含可以被多个程序共享的代码。这意味着可以在多个程序中使用同一份库代码的物理副本。

  2. 延迟加载:程序不需要在启动时加载所有依赖的库。它可以选择在运行时的某个特定点加载需要的库。

  3. API函数:操作系统提供的API函数允许程序在运行时打开、查询和关闭动态链接库。在Unix-like系统中,这些函数通常包括 dlopen(), dlsym(), dlclose()dlerror()

dl**函数族

dlopen(), dlsym(), dlclose(), 和 dlerror() 是在 Unix-like 系统中用于动态加载共享对象(通常是.so文件,在macOS上是.dylib文件)和执行它们的接口的函数。这组API被称为“动态链接器接口”。

  1. dlopen():

    • 用途:打开一个共享对象或可执行文件。
    • 原型:
      void *dlopen(const char *filename, int flag);
      
    • 参数:
      • filename:要加载的共享对象的路径。
      • flag:定义如何加载和解析对象。常见的标志包括 RTLD_LAZY(在初次调用时解析符号)和 RTLD_NOW(立即解析所有符号)。
    • 返回值:返回一个句柄,该句柄在后续的调用(如dlsym()dlclose())中使用。如果有错误,返回NULL。
  2. dlsym():

    • 用途:获取共享对象中函数或变量的地址。
    • 原型:
      void *dlsym(void *handle, const char *name);
      
    • 参数:
      • handle:由 dlopen() 返回的句柄。
      • name:要查找的符号的名称。
    • 返回值:返回符号的地址。如果有错误,返回NULL。
  3. dlclose():

    • 用途:关闭 dlopen() 打开的共享对象,并减少其引用计数。
    • 原型:
      int dlclose(void *handle);
      
    • 参数:
      • handle:由 dlopen() 返回的句柄。
    • 返回值:成功时返回0,失败时返回非零值。
  4. dlerror():

    • 用途:返回描述上一次调用 dlopen(), dlsym(), 或 dlclose() 时出现的错误的字符串。
    • 原型:
      char *dlerror(void);
      
    • 返回值:如果没有错误,返回NULL。否则,返回描述错误的字符串。

使用这些函数可以在运行时动态地加载、链接和调用共享库中的函数,而不需要在编译时静态地链接它们。这为编写可插拔和可扩展的代码提供了很大的灵活性。

综合案例

以下是一个简单的示例,演示了如何使用 dlopen(), dlsym(), dlclose(), 和 dlerror() 来动态加载一个共享库,并调用其中的函数。

假设我们有一个共享库 libgreeting.so,其中包含一个函数 void greet(const char* name)

libgreeting.c:

#include <stdio.h>

void greet(const char* name) {
    printf("Hello, %s!\n", name);
}

可以使用以下命令编译此共享库:

gcc -shared -o libgreeting.so libgreeting.c -fPIC

现在,我们将写一个程序来动态加载这个共享库,并调用 greet() 函数:

main.c:

#include <stdio.h>
#include <dlfcn.h>

int main() {
    void* handle;
    void (*greet_func)(const char*);

    char* error;

    handle = dlopen("./libgreeting.so", RTLD_LAZY);
    if (!handle) {
        fprintf(stderr, "%s\n", dlerror());
        return 1;
    }

    // 清除现有的错误,如果有的话
    dlerror();

    greet_func = (void (*)(const char*)) dlsym(handle, "greet");
    if ((error = dlerror()) != NULL)  {
        fprintf(stderr, "%s\n", error);
        return 1;
    }

    greet_func("world");

    dlclose(handle);
    return 0;
}

编译主程序:

gcc main.c -o main -ldl

运行 main,应该看到输出 Hello, world!

这个示例展示了如何使用动态链接器接口来在运行时加载共享库,并动态地调用其中的函数。这为编写灵活、可插拔的程序提供了可能性。

注1:

gcc -shared -o libgreeting.so libgreeting.c -fPIC

这个命令是使用 gcc 编译器来生成一个共享库。让我们一步步地解析这个命令:

  1. gcc:

    • 这是GNU C编译器。它用于编译C程序。
  2. -shared:

    • 这个选项告诉编译器我们希望生成一个共享库,而不是可执行文件。共享库(在Linux中通常是 .so 文件,在macOS中是 .dylib 文件)可以被多个程序共享并在运行时动态加载。
  3. -o libgreeting.so:

    • -o 选项用于指定输出文件的名称。在这里,我们要生成的共享库名称为 libgreeting.so
  4. libgreeting.c:

    • 这是我们要编译的源文件。它包含了我们的代码,特别是 greet 函数的实现。
  5. -fPIC:

    • 这是一个编译选项,意为“生成位置无关代码(Position Independent Code)”。位置无关代码意味着生成的代码可以在任何地址执行,这对于共享库是必要的,因为我们不知道加载它的程序将把它放在何处。
    • 当创建共享库时,使用 -fPIC 是很重要的,因为它确保库中的代码不依赖于任何固定的地址。

总之,这个命令告诉 gcclibgreeting.c 源文件生成一个名为 libgreeting.so 的共享库,并确保生成的代码是位置无关的。

注2:

gcc main.c -o main -ldl

-ldl 是一个 gcc 编译选项,用于链接程序时链接到特定的库。在这种情况下,它告诉链接器链接到动态链接器的库。具体来说,-l 选项告诉链接器链接到一个库,而 dl 指定了库的名字(在这里是 libdl.solibdl.a)。

这里的 “dl” 指的是 “dynamic linking”(动态链接),它是一个库,提供了用于动态加载共享对象、查询它们的符号等操作的函数。这就是我们在前面的例子中使用 dlopen(), dlsym(), dlclose(), 和 dlerror() 函数的原因。

为了能够在程序中使用这些函数,并在运行时解析它们的地址,需要链接到 libdl。这就是为什么我们需要 -ldl 选项。

简而言之:

  • -l: 告诉 gcc 我们要链接到一个库。
  • dl: 指定我们要链接到的库的名字,即动态链接库(libdl)。

因此,-ldl 确保我们的程序被正确地链接到 libdl,从而可以使用动态链接相关的函数。


总之,运行时链接提供了以下优点:

  • 共享代码:多个程序可以共享同一个库的物理副本。
  • 模块化:程序可以根据需要加载或卸载特定模块。
  • 更新和修补:可以通过替换库文件来更新或修补程序的部分,而无需重新编译或重新链接整个程序。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

运行时链接 的相关文章

随机推荐

  • 利用GeoHash实现逆地理编码(经纬度坐标转换行政区划)

    目录 前言 理解GeoHash GeoHash精度 GeoHash特征 GeoHash规律 逆地理编码 实现逆地理编码的基本思路 1 全国范围内6位精度GeoHash计算 2 获取全国范围内区 县 三级市级别行政区划地址围栏点 3 计算6位
  • 监督学习和无监督学习

    文章目录 监督学习和无监督学习 监督学习算法包括 无监督学习算法包括 OpenCV十个子类 举例 监督学习和无监督学习 监督学习和无监督学习是机器学习领域中两种不同的学习范式 它们之间的区别在于数据的标签或标记的可用性以及学习任务的性质 监
  • Python_Logging日志模块(一)

    一 日志的作用 展现当前程序的活动情况 记录程序的运行轨迹 规范稳定的日志可以帮助开发者迅速定位程序的问题 二 日志的内容 正常情况下 一条完整的日志应该包含调用日志的时间戳 数字形式的日志级别 调用日志的实例化函数的路径 线程名 抛出的活
  • sheel脚本

    sheel脚本 sheel脚本 sheel脚本 sheel脚本的工作方式有两种 交互式和批处理 交互式 用户输入一条就立即执行 批处理 由用户实现编写好一个完整的sheel脚本 sheel会一次执行脚本中诸多命令 脚本中不仅会用到一般的li
  • 测试用例设计方法之等效类,边界值

    概念 等价类划分是一种黑盒测试方法 把无限的测试变成有限的测试 把所有可能的输入数据 即程序的输入域划分成若干等价类 然后从每一个等价类中选取少数具有代表性的数据作为测试用例 依据需求将输入 特殊情况下会考虑输出 划分为若干个等价类 从等价
  • 红帽linux认证有哪些方向

    红帽Linux认证有以下几个方向 RHCSA 红帽认证系统管理员 该认证是红帽认证中的初级认证 主要考察考生对Linux系统管理的掌握程度 包括系统安装 文件系统管理 用户和组管理 网络管理等 RHCE 红帽认证工程师 该认证是红帽认证中的
  • 高德地图定位

    高德地图开放平台 获取key 获取key值后 将其在index html中引入 然后来到App vue下 即根组件下 一进项目就可以获取定位 所以在钩子函数created 中实现定位功能
  • OpenAi 嵌入

    什么是嵌入 OpenAI 的文本嵌入衡量文本字符串的相关性 嵌入通常用于 搜索 结果按与查询字符串的相关性排序 聚类 其中文本字符串按相似性分组 推荐 推荐具有相关文本字符串的项目 异常检测 识别出相关性很小的异常值 多样性测量 分析相似性
  • 2018-2019-2 网络对抗技术 20165322 Exp2 后门原理与实践

    2018 2019 2 网络对抗技术 20165322 Exp2 后门原理与实践 目录 实验准备 后门概念 常用后门工具 实验内容与步骤 使用netcat获取主机操作Shell cron启动 使用socat获取主机操作Shell 任务计划启
  • 阿里带火的中台到底是什么?白话中台战略

    作者 王健 ThoughtWorks首席咨询师 十多年国内外大型企业软件设计开发 团队组织转型经验 一直保持着对技术的热爱 热衷于技术分享 目前专注在企业平台化转型 中台战略规划 微服务架构与实施 大型遗留系统服务化改造 敏捷精益转型 以及
  • IOS工程添加目录

    问题 ios工程和资源工程是分开的 需要将工程外的一个文件夹导入到ios工程中 以前是直接拷贝一份放在frameworks runtime src proj ios mac中 这样操作的缺点就是 修改了公共的资源后 还需要再修改ios工程下
  • 微信小程序的computed的使用

    1 官方参考地址 computed 微信开放文档 qq com 2 自定义组件component和behaviors component参考地址 自定义组件 微信开放文档 qq com behaviors参考地址 behaviors 微信开
  • Solidity中引入的SPDX是什么

    Solidity中引入的SPDX是什么 起因 Solidity 0 6 8 要求引入 SPDX 许可证 否则会出现警告 Warning SPDX license identifier not provided in source file
  • MyBatis万能插入语句

    MyBatis万能插入语句 前言 最近需要做一个动态新增数据的接口 表名 列名 数据都是动态传进来的 需要一个接口就可以把所有表数据新增成功 第一种方式 首先看Mapper dao层 接口 插入数据 param tableName 表名 p
  • linux 解压所有以zip结尾的文件_Linux的压缩/解压缩文件处理 zip & unzip

    Linux的压缩 解压缩命令详解及实例 压缩服务器上当前目录的内容为xxx zip文件 zip r xxx zip 解压zip文件到当前目录 unzip filename zip 另 有些服务器没有安装zip包执行不了zip命令 但基本上都
  • C++中vector的使用

    向量std vector是一种对象实体 能够容纳许多各种类型相同的元素 包括用户自定义的类 因此又被称为序列容器 与string相同 vector同属于STL Standard Template Library 中的一种自定义的数据类型 可
  • VTK“静态编译”与“动态编译”的区别:

    静态编译 与 动态编译 的区别 静态编译就是在编译的时候把所有的模块都编译进可执行文件 exe 里去 当启动这个可执行文件时所有的模块都已加载进来 动态编译则是编译的时候需要的模块都没有编译进去 一般情况下可以把这些模块都编译成动态链接库D
  • exec族函数配合fork使用(linux系统编程)

    execl 函数配合fork 函数 在执行A程序的过程中去执行B程序 代码B 用来改文件中的数值 include
  • Google签名证书和base64密钥

    keystore重点说明 1 打包aab时 需要自己创建当前应用的keystore 这个是开发者的应用的keystore 以后上传这个应用都使用这个keystore 2 Google的签名证书 作用是当应用上传Google商店后 Googl
  • 运行时链接

    基本概念 运行时链接 是在程序运行时 而非编译时或加载时 将程序代码与其依赖的库代码进行链接的过程 动态链接在程序启动时或实际运行过程中通过API函数完成 这种方式的主要优点是它允许程序在运行时加载和卸载不同的库模块 从而实现更高的模块化和