深入Os--动态链接

1.动态链接库的使用
动态库支持以两种模式使用,一种模式下,在程序加载运行时,完成动态链接。一种模式下,在程序运行中,完成动态链接。
1.1.程序加载运行时完成动态链接
我们通过一个实例介绍程序加载运行时,使用动态库的方式
在这里插入图片描述

(1). 构建动态库
动态库源文件及makefile位于dynamic
a.t1.cpp

// t1.cpp
int addcnt = 0;
void addvec(int *x, int *y, int *z, int n)
{int i;addcnt++;for (i = 0; i < n; i++)z[i] = x[i] + y[i];
}

b.t2.cpp

// t2.cpp
int mulcnt = 0;
void multvec(int *x, int *y, int *z, int n)
{int i;mulcnt++;for (i = 0; i < n; i++)z[i] = x[i] * y[i];
}

c.makefile

main: t1 t2 dynamict1:g++ -fpic -std=c++11 t1.cpp -c
t2:g++ -fpic -std=c++11 t2.cpp -cdynamic:g++ -std=c++11 -shared t1.o t2.o -o libt.soclean:rm *.o libt.so *.txt

d.通过执行make完成构建。注意编译动态库源文件时需指定-fpic,基于.o得到动态库需指定-shared

(2).提供动态库导出符号声明文件
动态库导出符号声明文件放在include。
a.t.h

#ifndef _T_H
#define _T_H
extern int addcnt;
void multvec(int *x, int *y, int *z, int n);
void addvec(int *x, int *y, int *z, int n);
#endif

上述除了导出函数,我们还导出了变量addcnt。变量的声明需加上extern,否则会被视为变量定义。

(3).主程序使用动态库导出符号
a.主程序为main.cpp

#include <stdio.h>
#include "t.h"int x[2] = {1, 2};
int y[2] = {3, 4};
int z[2];int main()
{addvec(x, y, z, 2);printf("z=[%d %d]\n", z[0], z[1]);printf("addcnt_%d\n", addcnt);return 0;
}

我们采用加载运行时完成动态链接方式使用动态库时,在使用动态库导出符号时,需要先声明符号。然后直接使用即可。
上述使用了动态库导出的addvec,addcnt
b.构建可执行程序的makefile

main:g++ main.cpp -std=c++11 -I./include -L./dynamic -lt
clean:rm a.out *.o *.txt

我们采用加载运行时完成动态链接方式使用动态库时,构建可执行程序时,需通过-L -l来指定要链接的动态库的位置信息。-I用于指定编译期间头文件搜索路径。

(4).启动可执行程序
若上述编译完毕后,我们直接在a.out所在目录通过命令行执行./a.out是不行的。
在这里插入图片描述
因为类似编译链接过程需通过-L -l来指定要链接的动态库的位置信息。加载运行时,可以通过设置LD_LIBRARY_PATH来指定要链接的动态库的位置信息。上述结构下,我们提供s.sh。

// s.sh
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./dynamic
./a.out

这样执行./s.sh即可正常启动。LD_LIBRARY_PATH用于在程序启动运行时告知搜索程序依赖的动态库的路径。
要查看可执行程序依赖那些动态库,可使用ldd a.out
在这里插入图片描述

1.2.程序运行期间完成动态链接
我们通过一个实例介绍程序运行期间,使用动态库的方式。
在这里插入图片描述
(1). 构建动态库
和1.1部分相同。

(2).主程序中使用动态库导出符号
注意,运行期间使用动态库时,我们并不需要动态库导出符号声明文件。
因为使用导出符号的方式是通过dlsym直接取得导出符号地址后,转换为相应类型后使用。
a.主程序为main.cpp
这里的main.cpp放置在demo下

#include <iostream>
#include <dlfcn.h>int x[2] = {1,2};
int y[2] = {3,4};
int z[2];typedef void (*AddVec)(int*, int*, int*, int);
int main()
{void *handle;AddVec addvec = nullptr;char *error;handle = dlopen("libt.so", RTLD_LAZY);if(!handle){printf("%s\n", dlerror());return 0;}addvec = (AddVec)dlsym(handle, "addvec");if((error = dlerror()) != NULL){printf("%s\n", error);dlclose(handle);return 0;}int* addcnt = (int*)dlsym(handle, "addcnt");if((error = dlerror()) != NULL){printf("%s\n", error);dlclose(handle);return 0;}addvec(x, y, z, 2);printf("z = [%d %d],cnt_%d\n", z[0], z[1], *addcnt);dlclose(handle);return 0;
}

我们采用运行期间完成动态链接的方式使用动态库,在使用动态库导出符号时,通过dlsym取得导出符号地址后,转换为匹配类型后,即可使用。上述使用了动态库导出的addvec,addcnt

b.构建可执行程序的makefile
makefile放置在demo。

main:g++ -std=c++11 -rdynamic main.cpp -I../include -ldl
clean:rm a.out *.o *.txt

我们采用运行期间完成动态链接方式使用动态库时,构建可执行程序时,不需要通过-L -l来指定要链接的动态库的位置信息。因为编译链接过程尚未用到运行期间要链接的动态库。但需指定-rdynamic -ldl,因为我们此时需要链接到服务于运行期间动态连接的动态库dl。
在这里插入图片描述
(3).启动可执行程序
类似的,我们在启动前需通过LD_LIBRARY_PATH来指定dlopen中搜索动态库的路径信息。
我们的放置在demo下的s.sh为

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../dynamic
./a.out

但执行./s.sh时,报错了:
在这里插入图片描述
因为我们采用c++方式编译动态库时,库内addvec的符号实际编译出的符号名称为:
在这里插入图片描述
这是因为c++编译器对编译时,针对函数类型会结合其形参为其构建符号名称。c编译器不会。
c++支持同名函数重载,所以,这样是需要的。c不支持同名函数重载,所以,不需要。

上述报错是因为我们通过dlsym取出addvec符号地址时,通过名称addvec在动态库中找不到匹配的符号。
为了正常使用dlsym取得导出符号地址:
(1).我们要么将dlsym传入的符号名修改为_Z6addvecPiS_S_i
(2).要么通过设置使得c++编译时,针对addvec导出符号不要采用符号重新命名机制。我们只需在动态库源文件符号定义处,添加extern "C"修饰即可。若我们采取了此种方式,应该同步在类库导出符号声明文件中为addvec的声明也添加extern "C"修饰。这样,1.1中使用动态库时,也会直接采用addvec来在动态库中定位符号的定义位置。

针对变量类型导出符号,如addcnt,c++编译器不会对符号执行重新命名。所以,直接使用符号名即可。

值得注意的是,添加extern "C"后由于关闭结合形参重命名机制,所以,此时也就不允许同名符号重载了。

int addcnt = 0;
void addvec(int *x, int *y, int *z, int n)
{int i;addcnt++;for (i = 0; i < n; i++)z[i] = x[i] + y[i];
}void addvec(int *x, int *y, int *z)
{int i;i = 0;i++;
}

上述内容,作为t1.cpp内容时,可正常编译。

int addcnt = 0;
extern "C" void addvec(int *x, int *y, int *z, int n)
{int i;addcnt++;for (i = 0; i < n; i++)z[i] = x[i] + y[i];
}extern "C" void addvec(int *x, int *y, int *z)
{int i;i = 0;i++;
}

上述内容作为t1.cpp内容时,无法编译通过。因为存在同名符号问题。
在这里插入图片描述

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

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

相关文章

4G基站BBU、RRU、核心网设备

目录 前言 基站 核心网 信号传输 前言 移动运营商在建设4G基站的时候&#xff0c;除了建设一座铁塔之外&#xff0c;更重要的是建设搭载铁塔之上的移动通信设备&#xff0c;这篇博客主要介绍BBU&#xff0c;RRU以及机房的核心网等设备。 基站 一个基站有BBU&#xff0c;…

Liunx系统使用超详细(四)~文件/文本相关命令1

目录 一、mkdir命令 1.1基本语法 1.2常用示例 1.2.1创建目录 1.2.2创建多级目录 1.2.3设置权限 1.2.4递归修改权限 1.2.5显示帮助信息 二、touch命令 2.1基本语法 2.2常用示例 2.2.1创建新的空文件 2.2.2更新现有文件的访问和修改时间戳 2.2.3创建多个文件 2.2.…

【Midjourney实战】| 新年红包、元宝、灯笼、福袋生成

文章目录 1 红包生成2 灯笼生成3 福袋生成4 元宝生成 1 红包生成 之前我们生成了新年礼盒&#xff0c;这一期我们来生成一些过年时特有的元宝和红包 首先&#xff0c;最重要的是画面主体 red envelope&#xff08;红包&#xff09;颜色红色 黄色的 red and yellow 为了后期方…

跳水比赛(C++)

系列文章目录 进阶的卡莎C++_睡觉觉觉得的博客-CSDN博客数1的个数_睡觉觉觉得的博客-CSDN博客双精度浮点数的输入输出_睡觉觉觉得的博客-CSDN博客足球联赛积分_睡觉觉觉得的博客-CSDN博客大减价(一级)_睡觉觉觉得的博客-CSDN博客小写字母的判断_睡觉觉觉得的博客-CSDN博客纸币(…

Web漏洞分析-SQL注入XXE注入(下)

随着互联网的不断普及和Web应用的广泛应用&#xff0c;网络安全问题愈发引起广泛关注。在网络安全领域中&#xff0c;SQL注入和XXE注入是两个备受关注的话题&#xff0c;也是导致许多安全漏洞的主要原因之一。本博客将深入研究这两种常见的Web漏洞&#xff0c;带您探寻背后的原…

GNSEC 2022年第8届全球下一代软件工程线上峰会-核心PPT资料下载

一、峰会简介 新一代软件工程是指利用新的理论、方法和技术&#xff0c;在软件开发、部署、运维等过程中&#xff0c;实现软件的可控、可预测、可维护的软件生产方式。它涵盖了多个领域&#xff0c;如软件开发、测试、部署、运维等&#xff0c;旨在提高软件生产效率和质量。 …

103.进程概述

目录 1.并行和并发 区别&#xff1a; 2.PCB 3.进程状态 4. 进程命令 从严格意义上来讲&#xff0c;程序和进程是两个不同的概念&#xff0c;他们的状态&#xff0c;占用的系统资源都是不同的。 程序&#xff1a;程序是一种静态实体&#xff0c;是存储在计算机存储介质上的…

判断三角形-第11届蓝桥杯选拔赛Python真题精选

[导读]&#xff1a;超平老师的Scratch蓝桥杯真题解读系列在推出之后&#xff0c;受到了广大老师和家长的好评&#xff0c;非常感谢各位的认可和厚爱。作为回馈&#xff0c;超平老师计划推出《Python蓝桥杯真题解析100讲》&#xff0c;这是解读系列的第12讲。 判断三角形&#…

AOC computer monitor

【窗口增亮】关闭就没掉了

Java异常讲解

&#x1f435;本篇文章将对异常相关知识进行讲解 一、异常的结构 在程序执行的过程中出现的一些问题叫做异常&#xff0c;异常其实是一个一个类&#xff0c;每一种异常都代表一个类 1.1 几种常见的异常 System.out.println(10/0); //算数异常 //Exception in thread "m…

LDAP协议和AD活动目录的讲解

目录 LDAP协议 LDAP基本概念 LDAP目录的数据结构 LDAP交互过程以及相关报文 AD&#xff08;Active Directory&#xff09; AD基本概念 AD域与工作组、本地组的区别 AD DS&#xff08;AD域服务&#xff09; 信任关系 组策略和安全组 LDAP协议 LDAP基本概念 LDAP&…

2024年程序员面对经济下行的解决方式竟然是……

近些年大环境不好&#xff0c;经济下行的压力给到了我们每一个普通人的身上&#xff1a;降薪是潮流&#xff0c;裁员是趋势&#xff0c;找不到工作是常态。 在这样的环境下&#xff0c;我们曾一天三份工&#xff0c;只为家人温饱&#xff1b; 我们也曾一周七天连轴转&#xf…

ProEasy机器人:快速上手使用机器人软件与编程(干货满满,好学不费脑)

一、安装机械手软件 如图所示&#xff0c;安装顺序为&#xff1a;先安装第一个&#xff0c;再安装第二个 二、快速认识学习掌握机械手软件重要功能 1.连接机械手 机械手默认出厂的ip为&#xff1a;“192.168.1.1”&#xff0c;在初次连接机械手前&#xff0c;必须把使用连接的…

k8s官方镜像代理加速

背景 大家可能在云原生领域需要部署周边的一些生态组件时&#xff0c;在国内遇到无法正常拉取镜像&#xff0c;显得就有点苦恼&#xff0c;不过没关系&#xff0c;常见的${{ registry_name }} 例如 “gcr.io”&#xff0c;“registry.k8s.io” Failed to pull image “registry…

AI Pika 生成进击的巨人动漫分镜案例

背景介绍 Pika 是一个使用 AI 生成和编辑视频的平台。它致力于通过 AI 技术使视频制作变得简单和无障碍。 Pika 1.0 是 Pika 的一个重大产品升级&#xff0c;包含了一个新的 AI 模型,可以在各种风格下生成和编辑视频,如 3D 动画&#xff0c;动漫&#xff0c;卡通和电影风格。…

springboot 整合 Spring Security+JWT 实现token 认证和校验

1.大概是这个样子 JWT 是什么&#xff1f; Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准&#xff08;(RFC 7519).该token被设计为紧凑且安全的&#xff0c;特别适用于分布式站点的单点登录&#xff08;SSO&#xff09;场景。JWT的声明…

【ArcGIS微课1000例】0078:创建点、线、面数据的最小几何边界

本实例为专栏系统文章:讲述在ArcMap10.6中创建点数据最小几何边界(范围),配套案例数据,持续同步更新! 文章目录 一、工具介绍二、实战演练三、注意事项一、工具介绍 创建包含若干面的要素类,用以表示封闭单个输入要素或成组的输入要素指定的最小边界几何。 工具位于:数…

Park Unpark

文章目录 当先调用park时&#xff1a;如果_counter0&#xff0c;这时候该线程阻塞&#xff0c;进入_cond阻塞&#xff0c;之后Unpark设置_counter为1后停止阻塞 当先调用Unpark时&#xff1a;此时先将_counter设置为1&#xff0c;当后面出现park时一判断_counter为1&#xff0c…

IO多路复用(新)

1.前景回顾 无论是阻塞IO还是非阻塞IO&#xff0c;用户应用在一阶段都需要调用recvfrom来获取数据&#xff0c;差别在于无数据时的处理方案&#xff1a; 如果调用recvfrom时&#xff0c;恰好内核没有数据&#xff0c;那么阻塞IO会使用户进程阻塞&#xff0c;非阻塞IO使CPU进行空…

CMMI5大成熟度等级和4大过程域

CMMI&#xff08;Capability Maturity Model Integration&#xff0c;能力成熟度模型集成&#xff09;模型系列是帮助组织改进其过程的最佳实践的集合。这些模型由来自产业界、政府以及软件工程研究所&#xff08;Software Engineering Institute&#xff0c; SEI&#xff09;的…