C++:Article : 链接器(三):库与可执行文件的生成

news2024/11/15 1:38:53

链接器:库与可执行文件

  • 1. 静态库
    • 1.1 静态链接下,可执行文件如何生成
  • 2. 动态库
    • 2.1 动态库特点以及与静态库使用方式差异
    • 2.2 动态库和静态库使用时间
  • 3. load-time dynamic linking(加载时动态链接)
    • 3.1:阶段一:将动态库信息写入可执行文件
    • 3.2:阶段二:加载可执行文件时依据动态库信息进行动态链接
  • 4:第二种动态链接:run-time dynamic linking(运行时动态链接)
  • 5:动态链接下可执行文件的生成
    • 5.1:dynamic段
    • 5.2:GOT(Global offset table)
  • 6. 动态库VS静态库
  • 6.1 动态库的优点
      • 6.1.1 插件
      • 6.1.2 动态库用在多语言上
    • 6.2 :动态库缺点
      • 6.2.1 :启动性能稍弱
      • 6.2.2:兼容性问题(版本依赖问题)
  • 7.静态库优点
  • 8. Linux下创建静态库
    • 8.1 Linux 下使用静态库
    • gcc -c main.cpp gcc -o hello main.o libhello.a
  • 9. Linux 系统下创建动态库
    • gcc -shared -fPIC -o libhello.so hello.o
    • 9.1. 使用.so动态库

链接器可操作的最小单元是目标文件,也就是说无论我们见到的是静态库,动态库,可执行文件,都是基于目标文件构建出来的
给定目标文件以及链接选项,链接器可以生成两种库,静态库和动态库。

在这里插入图片描述
💚💚💚
一言以蔽之我们通过三张图来区分动态库和静态库
在这里插入图片描述
💚💚💚
静态库的特点
在这里插入图片描述
💚💚💚
动态库的特点
在这里插入图片描述

1. 静态库

静态库在windows 环境下是以 .lib为后缀文件, 在 linux 环境下是以 .a为后缀文件。

💚💚💚
你可以将静态文件理解成由:一堆目标文件打包而成,使用者只需要使用其中的函数无需关注该函数来自哪个目标文件
找到函数来自哪个目标文件是由链接器来完成的,而且静态库中的所有目标文件并不会都被使用到,而是链接器用到哪个就使用哪个。

在这里插入图片描述

1.1 静态链接下,可执行文件如何生成

在上一节中我们知道,可以将静态链接简单的理解为,链接器将使用到的目标文件集合进行拼装,拼装之后就可以生成可执行文件。
在这里插入图片描述
从上图中我们可以看出,可执行文件的特点:

  1. 可执行文件和目标文件一样,也是由代码段和数据段组成。
  2. 每个目标文件的数据段被合并到可执行文件的数据段,每个文件的代码段被合并到可执行文件的代码段
  3. 目标文件的符号表,并没有被合并到 可执行文件中,因为可执行文件不需要符号表。
  4. 目标文件和可执行文件本质上没有区别,但是可执行文件和目标文件的区别又在于:可执行文件有一个入口函数,即main 函数,入口函数, 在执行过程中会用到可执行文件所用代码段和数据段内容,main是被操作系统 Operating System 调用。

2. 动态库

  1. 由于静态链接会将用到的目标文件合并到可执行文件中,如果有多个可执行文件需要用到一个静态库,那么就会出现这样一个现象:
  2. 生成的所有可执行文件当中都有一份一模一样的静态库中的代码,那么这个对内存和硬盘来说是一个极大地浪费。
  3. 💚💚💚💚
  4. 所以动态链接变应运而生。

2.1 动态库特点以及与静态库使用方式差异

  1. 动态库(Dynamic Library)又叫共享库(Shared Library)动态链接库等。
  2. 在Windows下就是我们常见的 DLL库,在 Linux 下以 .so库为后缀,同时以后 lib 为前缀
  3. 本质上动态库还是由 :代码段,数据段,符号表组成,但是动态库和静态库的使用方和使用时间是不一样的。
    在这里插入图片描述
  4. 如上图所示,可执行文件链接静态库是将,静态库所有文件都拷贝一份给可执行文件,并和可执行文件合并。
  5. 动态链接:可执行文件链接动态库,仅仅是将动态库用到的目标文件的引用合并到可执行文件中。

2.2 动态库和静态库使用时间

静态库其实是在编译期间(Compile time)链接使用,那么动态链接是在什么时候使用了 ?

  1. 加载时动态链接(load-time dynamic linking)
  2. 运行时动态链接(run-time dynamic linking)

3. load-time dynamic linking(加载时动态链接)

  1. load-time翻译过来就是加载,比如:游戏中经常出现一句话:“加载中,请稍候!”,这里的其实就是指程序的加载,而所谓程序的加载就是把可执行文件从磁盘搬到内存的过程,动态链接就出现在这个过程。
  2. 当把可执行文件赋值到内存后,且在程序开始运行之前,操作系统会查找可执行文件依赖的动态库信息(主要是:动态库的名字和存放路径),当找到该动态库后,就将动态库从磁盘搬到内存,并进行符号决议。
  3. 如果符号决议这个过程没问题,那么一切准备工作就绪,程序就可以开始执行了,如果找不到相应的动态库或符号决议失败,那么就会有相应的错误信息,报告给用户,程序就会运行失败。
    💚💚💚
    总结:从总体上看,加载时动态链接可以分为两个阶段:
    阶段一:将动态库信息写入可执行文件。
    阶段二:加载可执行文件时依据动态库信息进行动态链接。

3.1:阶段一:将动态库信息写入可执行文件

在编译链接生成可执行文件时,需要将使用的动态库加入到链接选项中,比如在 Linux 下 引用 libMath.so 就需要将 libMath.so加入到链接选项中。

  • 如果libMath.so 放到了 /usr/lib 下,那么使用命令 gcc …-|Math -L/usr/lib 进行编译链接,就可以让生成的可执行文件中保存了依赖的动态库信息,你可以 在 Linux 使用 ldd 命令来查看。

3.2:阶段二:加载可执行文件时依据动态库信息进行动态链接

由于在阶段一生成的可执行文件中保存了动态库信息,当可执行文件加载完成后,就可以依据此信息进行动态库的查找以及顾浩决议了
很显然,你已经知道了静态库和动态库的区别:使用动态库的可执行文件当中仅仅保留相应信息,动态库的链接过程被推迟到了程序启动加载时。

4:第二种动态链接:run-time dynamic linking(运行时动态链接)

  • run-time dynamic linking运行时动态链接:不需要在编译链接时提供动态库信息,也就是说,在可执行文件被启动运行之前,可执行文件对所依赖的动态库信息一无所知,只有当程序运行到需要调用动态库所提供的代码时才会启动动态链接过程。
  • 相比加载时动态链接,运行时动态链接将链接这个过程推迟后推迟,推迟到了程序运行时。
  • 当代码中需要使用某个动态库所提供的函数,我们需要使用特定的 API 来运行时加载动态库,在 Windows 下可以通过 LoadLibrary 或者 LoadLibraryEx,这些API被调用后,同样是首先去找这些动态库,将其从磁盘 烤白到 内存,然后 查找程序依赖的函数是否在动态库中定义,这些过程完成后,动态库中的代码就可以被正常使用了。

5:动态链接下可执行文件的生成

  • 在静态链接下,链接器通过将各个目标文件的代码段合并并拷贝到可执行文件,因此静态链接下可执行文件当中包含了所依赖的所有代码和数据。
  • 然后动态链接并不是将动态库中的代码和数据拷贝到可执行文件中,而是将动态库的必要信息写入了可执行文件,,这样昂可执行文件在加载时就可以根据此信息进行动态链接,我们可以将该信息仅仅认为是动态库的名字,当然真实情况肯定比这要复杂些。
  • 在前面的章节中我们将可执行文件简单的换分为:数据段和代码段两段,在这里我们继续丰富下可执行文件中的内容,如下图所示:
    💚💚💚
    在数据段和代码段的基础上,新增了两段。即:dynamic段和 GOT(Global offset table)段,这两段内容就就是我们刚刚说的 必要信息。
    在这里插入图片描述

5.1:dynamic段

dynamic段中保存了可执行文件依赖哪些库,动态链接符号表的位置以及重定位表的 位置信息。

5.2:GOT(Global offset table)

6. 动态库VS静态库

6.1 动态库的优点

  • 在计算机历史中,最开始程序只能静态链接,但是人们很快发现,静态链接生成的可执行文件在磁盘空间浪费问题,因为对于每个程序来说都需要依赖 lib 库,在静态链接下每个可执行文件当中都有一份 libc代码和数据的拷贝。
  • 对于现代计算机来说,比如PC 机,通常会运行成百上千个程序(进程),且程序只有被加载到内存中才可以使用,如果使用静态链接那么在内存中就会有成百上千份同样的libc代码,这对以宝贵的内存资源是极大的挑战和浪费。

所以为了解决这个问题,程序员提出了 动态库

  • 动态库在内存中只需要一份 libc 代码,所有的程序共享这一份代码,因此极大的节省了内存资源,这也是为什么动态库又叫共享库。

  • 共享库还有一个强大之处就是:如果我们修改了动态库的代码,我们只需要重新编译动态库就可以而无需重新编译我们自己的程序
    (这是因为可执行文件仅仅保留动态库的必要信息,重新编译动态库不给你不会改变这些,只要你不修改动态库的名字和动态库导出的可供可执行文件使用的函数即可)。

  • 编译好的新动态库只需要简单的替换原有动态库,下一次运行程序就可以使用新的动态库,所以动态库的这种特性就极大的方便了程序升级和bug 修复。

  • 动态库的优点可不止这些:我们知道动态链接可以出现在运行时(run-time dynamic link), 动态链接的这种特性可以用于扩展程序能力,那么如何扩展了 ?答案就是插件

  • 动态库的强大 还体现在多语言上。

💚💚💚

6.1.1 插件

实现插件时,我们只需要实现规定好的几个函数,插件就可以运行,那么这个是怎么做到的呢 ?答案就是 : 动态链接

我们可以将插件以动态的方式实现。
试想一下:由于动态链接是在运行时,才知道使用了什么库,什么函数,在编译期间可执行文件对此是一无所知。
那么在编译链接可执行文件又是如何知道插件中定义了哪些函数呢 ?
这个就要求 所有插件实现函数都必须有一个统一的格式,程序在运行时间就可以按照这个函数(统一格式)来调用,这样我们写的插件就可以运行起来。

6.1.2 动态库用在多语言上

我们知道使用 Python 可以快速进行开发,但是 Python 的性能无法同 C++相比 (因为 Python 是解释型语言:程序执行速度慢。由于每个语句都是执行的时候才翻译,解释器是一句一句的翻译这样解释性语言,每执行一次就要翻译一次,效率比较低。适用一些脚本,网页等快速开发的功能)

那么是否有一种办法可以做到:既可以兼具 Python 的快速开发能力,也可以具备 C++的高性能了 ?
答案是肯定的。

💚💚💚💚
我们可以将C++代码编译成动态链接库,这样 Python就可以直接调用动态链接库中的函数,其实 不退单 Python Perl 以及 java等语言都是可以通过动态库的形式调用 C++代码的,所以动态库的使用使得同一个项目不同语言的混合编程称为可能 。

6.2 :动态库缺点

6.2.1 :启动性能稍弱

由于动态库是程序在加载时或运行时,才进行链接的,因此同静态链接相比,使用动态链接的程序在性能上要稍弱 静态链接。
💚💚💚💚
这是因为加载时动态链接,这会 减慢程序启动速度。
运行时动态链接:当首次调用动态库函数时,程序会被暂停,当链接过程结束后才可以继续。

这点性能损耗,相比动态库的优点还是微乎其微的。

6.2.2:兼容性问题(版本依赖问题)

动态链接下的可执行文件不可以被独立运行(load-time dynamic link), 换句话说:如果没有提供所依赖的动态库或者动态库的版本和 可执行文件所依赖的版本不兼容,程序是无法启动的,这会给程序的安装部署带来很大的麻烦。

7.静态库优点

优点
静态链接时最古老也是最简单的链接技术,它的最大优点是:使用简单,编译好的可执行文件是完整的,这就消除了动态链接下 依赖的问题,没有了 依赖问题,这就给程序的安装和部署带来极大的方便。
比如 像微信这种数量级的系统,后端会部署在成千上万台机器上,这么多机器的安装部署以及升级会给运维带来极大的挑战,静态链接下的可执行文件由于不依赖任何其他库,部署会及其方便,仅仅用一个新的可执行文件覆盖就可以了。

缺点
静态库会导致可执行文件过大,且多个程序静态链接同一个精态库的话会导致 磁盘浪费问题。

8. Linux下创建静态库

库是一组预先编译好的方法集合,是计算机上的一类文件,提供给使用者或者一些开箱即用的变量,函数或类。
静态库:windows 下扩展名 .lib 而 Linux 下的扩展名为 .a 。

下面我们分析下载 Linux 系统下创建静态库步骤

  1. Linux 静态库名规范: lib[your_library_name].a : lib 为前缀,中间是静态库名,扩展名为 .a 。

  2. 将代码文件编译成目标文件 .o (hello.o) 请注意:带参数 -c ,否则直接编译为 可执行文件
    g++ -c hello.cpp

  3. 通过 ar 工具将目标文件打包成 .a 库文件
    ar -crv libhello.a hello.o

下面我们编写三个文件,分别是 hello.h hello.cpp main.cpp ,文件内容如下:

hello.h

#ifndef HELLO_H
#define HELLO_H
void hello_fun(const char* name);
#endif  // HELLO_H

hello.cpp

#include<iostream>
#include "hello.h"
void hello_fun(const char* name)
{
	printf("Hello %s!",name);
}

main.cpp

#include"hello.h"
int main()
{
	hello_fun("C++ static library");
	return 0;
}

在这里插入图片描述

8.1 Linux 下使用静态库

  1. 方法一: gcc main.cpp libhello.a -o main / g++ main.cpp libhello.a -o main
    在这里插入图片描述
    在这里插入图片描述

运行发现命令:gcc main.cpp libhello.a -o main 报错了,但是 g++ main.cpp libhello.a -o main就没有问题,这是什么原因了 ? 我们待会在分析

  1. 方法二 :

gcc -c main.cpp
gcc -o hello main.o libhello.a

gcc -c main.cpp
g++ -o main.exe main.o libhello.a

在这里插入图片描述
在这里插入图片描述

9. Linux 系统下创建动态库

动态库:
Windows 下扩展名:.dll (Dynamic-Link Libraries)
Linux 下扩展名 :.so (Shared Object)
命令:

gcc -shared -fPIC -o libhello.so hello.o

g++ -shared -fPIC -o libhello.so hello.o
在这里插入图片描述

9.1. 使用.so动态库

链接动态库到可执行文件

g++ -o main.exe main.cpp libhello.so
在这里插入图片描述

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

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

相关文章

【工具】FFmpeg|超大视频本地有损压缩,500MB变25MB(支持 Windows、Linux、macOS)

参考&#xff1a; 如何将一分钟长的1080p视频压缩至5MB以内&#xff1f;-知乎-滔滔清风近期HEVC扩展备用安装方法-B站-悲剧天下 总共三个步骤&#xff0c;安装FFmpeg、运行指令、打开视频。 亲测 500MB 变 25MB。 1 安装FFmpeg 对于不需要看教程可以自行完成安装的同学们&am…

MySQL基础案例——数据表的基本操作:创建表和修改表

目录 案例目的&#xff1a; 创建表&#xff1a; 创建offices&#xff1a; 创建employees表&#xff1a; 修改表&#xff1a; 将 employees 的 mobile 字段移动到 officeCode 字段后&#xff1a; 将 birth 字段名称改为 employee_birth: 修改 sex 字段&#xff0c;数据类…

TryHackMe-Looking Glass(boot2root)

Looking Glass 穿过镜子。仙境挑战室的续集。 端口扫描 循例nmap 又是一堆ssh&#xff0c;跟之前的玩法一样 找到正确的ssh端口之后后给了一段密文&#xff0c;要求输入secret才能进入ssh 这看起来非常像凯撒密码 唯一可识别的信息是Jabberwocky&#xff0c;我们找到了它 它…

IDA简单使用

今天来简单介绍一下逆向中常用到的另一个静态分析工具IDA&#xff0c;还是昨天那个打印demo&#xff08;64位&#xff09;&#xff1a; #include #include char a[] "https://www.vultop.com/"; int main(int argc, char* argv[]) { printf("%s", a)…

什么是微服务

目录 一、微服务介绍 1. 什么是微服务 2. 微服务由来 3. 为什么需要微服务&#xff1f; 3.1 最期的单体架构带来的问题 3.2 微服务与单体架构区别 3.3 微服务与SOA区别 4. 微服务本质 5. 什么样的项目适合微服务 6. 微服务折分与设计 6.1 微服务设计原则 7. 微服务…

linux gcc + openocd + stlink + cubeMX + cortex Debug

文章目录 运行环境&#xff1a;1.1 gcc1)下载并解压gcc2)环境配置 2.1 openocd1)下载并解压openocd2)环境配置&#xff08;没有权限就加sudo&#xff09; 3.1 stlink1)下载并双击安装stlink 4.1 cubeMX1)下载并解压cubeMX2)生成makefile工程 5.1 cortex Debug1)setting设置2)la…

冷链物流运转 3D 可视化监控,助力大数据实时监控

智慧物流是以信息化为依托并广泛应用物联网、人工智能、大数据、云计算等技术工具&#xff0c;在物流价值链上的 6 项基本环节&#xff08;运输、仓储、包装、装卸搬运、流通加工、配送&#xff09;实现系统感知和数据采集的现代综合智能型物流系统。随着冷链信息化、数字化发展…

史上最全! 瑞芯微RK3568核心板评估板资源分享!

▎瑞芯微RK3568芯片 高性能处理器&#xff1a;采用四核A55架构CPU&#xff0c;G52 GPU&#xff1b;内置NPU&#xff0c;可提供1T算力 高可靠性设计&#xff1a;支持DDR及CPU Cache全链路ECC 内置自研ISP图像处理器&#xff1a;8M30fps处理能力&#xff0c;强大的HDR功能&#…

Springboot Netty 实现自定义协议

Netty是由JBOSS提供的一个java开源框架&#xff0c;现为 Github上的独立项目。Netty提供异步的、事件驱动的网络应用程序框架和工具&#xff0c;用以快速开发高性能、高可靠性的网络服务器和客户端程序。 也就是说&#xff0c;Netty 是一个基于NIO的客户、服务器端的编程框架&…

《编程思维与实践》1039.字符组合

《编程思维与实践》1039.字符组合 题目 思路 先将字符串去重排序(保证每个组合中的字符按字典序),然后枚举出所有组合的情形,最后再进行字典序排序即可. 其中字符串的去重排序可以利用ASCII码值进行桶排序,关键在于如何枚举所有组合的情形. 每个位置有两种可能(选或不选),但至…

MongoDB 聚合管道的输出结果到集合($out)及合并结果到集合($merge)

上一篇文章&#xff0c;我们介绍了使用聚合管道完成文档之间的关联查询、以及如果将两个管道中的文档进行合并&#xff0c;如果需要进一步了解可以参考&#xff1a;MongoDB 聚合管道的文档关联查询($lookup)及管道合并($unionWith)https://blog.csdn.net/m1729339749/article/d…

ES索引管理

ES官方博客&#xff1a;https://elasticstack.blog.csdn.net/?typeblog 一、rolloverAPI https://elasticstack.blog.csdn.net/article/details/102728987 1.1 rollover命令 POST /log_alias/_rollover { "conditions":{ "max_age":"…

Node 09 MongoDB的使用

MongoDB 简介 Mongodb 是什么 MongoDB 是一个基于分布式文件存储的数据库&#xff0c;官方地址 https://www.mongodb.com/ 数据库是什么 数据库&#xff08;DataBase&#xff09;是按照数据结构来组织、存储和管理数据的 应用程序 数据库的作用 数据库的主要作用就是 管理…

jsp家庭农场投入品信息管理系统Myeclipse开发mysql数据库web结构jsp编程计算机网页项目

一、源码特点 jsp家庭农场投入品信息管理系统是一套完善的java web信息管理系统 serlvet dao bean 开发&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发…

如何理解PCB布线3W规则

我们平时在PCB布线的时候&#xff0c;对于比较重要的信号都要做特殊处理&#xff0c;比如包地或者时“3W”&#xff0c;所谓3w指的是线与线之间的间距要满足三倍的线宽&#xff0c;那么我们怎么理解这个3W原则呢&#xff0c;他是如何降低信号之间的串扰的呢&#xff1f; 我们要…

连网介质及设备详解

文章目录 一、网卡1. 有线网卡2. 无线网卡3. 光纤网卡 二、网线1. 双绞线2. 光缆 三、交换机1. 什么是交换机2. 交换机分类 一、网卡 网卡分为三类&#xff1a;有线网卡、无线网卡、光纤网卡 1. 有线网卡 多数台式计算机自带&#xff0c;采用 RJ-45 制式接口 通过双绞线传输…

Hive2安装Tez计算引擎

一、Tez介绍 ApacheTEZ项目旨在构建一个应用程序框架&#xff0c;该框架允许使用复杂的有向无环图来处理数据。 它当前构建在Apache Hadoop YARN之上。 Tez的2个主要设计主题是&#xff1a; 通过以下方式增强最终用户的能力&#xff1a; 富有表现力的数据流定义API 灵活的输入…

ICV:车载毫米波雷达中国市场有望在2025年实现30亿美元的市场规模

近日&#xff0c;专注于前沿科技领域的国际咨询机构ICV发布了全球车载毫米波雷达的市场研究报告&#xff0c;汽车毫米波&#xff08;mmWave&#xff09;雷达基于频率为77 GHz的电磁波&#xff0c;具有高精度和准确性&#xff0c;可用于目标检测。这种技术有着广泛的应用&#x…

Dubbo面试大全

Dubbo面试题 1.Dubbo 是什么&#xff1f; Dubbo是阿里巴巴开源的分布式&#xff0c;高性能的透明化的RPC服务框架&#xff0c;提供服务自动注册&#xff0c;自动发现等高效服务治理方案&#xff0c;可以和Spring框架可以无缝衔接。 2.Dubbo的由来 你们的项目为什么会使用Du…

论文阅读 关联规则挖掘综述

这是一篇关联规则挖掘的综述&#xff0c;也记录下自己的心得笔记 A comprehensive review of visualization methods for association rule mining: Taxonomy, Challenges, Open problems and Future ideas 文章目录 摘要1、介绍2、关联规则挖掘是个小东西2.1、数值关联规则挖…