静态链接:空间与地址分配

news2024/11/27 14:51:02

前言

我们终于走到了链接这一步,对于链接这一步,它是将多个输入目标文件链接后输出一个可执行文件。我们拿两个程序a.c和b.c来举例说明链接的过程。

a.c:

/* a.c */
extern int shared;

int main(){
	int a = 100;
	swap(&a,&shared);
}

b.c:

/* b.c */
int shared = 1;

void swap(int* a,int* b){
	*a ^= *b ^= *a ^= *b;//这是位操作符异或, 二进制的数学运算。这是一种不需要临时变量就可以交换ab的方法
}

使用gcc将上述两个程序编译成目标文件a.o,b.o:

gcc -c a.c b.c

我们首先要关注的是链接后的输出文件的空间与地址分配问题。

1.按序叠加

一个最简单的方案就是将输入的目标文件按照次序叠加起来,如下图所示:

在这里插入图片描述

按序叠加的优点是做法很简单,直接将各个目标文件依次合并;缺点是在有很多输入文件的情况下,输出文件将会有很多零散的段,每个段都需要有一定的地址和空间对齐要求,会造成内存空间大量的内部碎片,非常浪费空间。

相似段合并

一个更实际的方法是将相同性质的段合并到一起,将所有输入文件的“.text”合并到输出文件的“.text”段,接着是“.data”段、“.bss”段等,如下图所示:

在这里插入图片描述

需要注意的是,“.bss”段在目标文件和可执行文件中并不占用文件的空间,但是它在装载时占用地址空间。所以链接器在合并各个段的同时,也将“.bss”合并,并且分配虚拟空间。现在的链接器空间分配的策略基本上都采用上述方法中的第二种,使用这种方法的链接器一般都采用一种叫两步链接(Two-pass Linking) 的方法。整个链接过程分两步。

第一步空间与地址分配: 扫描所有的输入目标文件,并且获得它们的各个段的长度、属性和位置,并且将输入目标文件中的符号表中所有的符号定义和符号引用收集起来,统一放到一个全局符号表。这一步中,链接器将能够获得所有输入目标文件的段长度,并且将它们合并,计算出输出文件中各个段合并后的长度与位置,并建立映射关系。

第二步符号解析与重定位: 使用上面第一步中收集到的所有信息,读取输入文件中段的数据、重定位信息,并且进行符号解析与重定位、调整代码中的地址等。事实上第二步是链接过程的核心,特别是重定位过程。这一步我们下一篇文章会详细介绍。

空间与地址分配

使用ld链接器将a.o和b.o链接起来:

ld a.o b.o -e main -o ab

-e main表示将main函数作为程序入口,ld链接器默认的程序入口为_start。

-o ab表示链接输出文件名为ab,默认为a.out。

使用objdump来查看链接前后地址的分配情况:

在这里插入图片描述

链接前后的程序中所使用的地址已经是程序在进程中的虚拟地址,即我们关心上面各个段中的VMA (Virtual Memory Address)Size,而忽略文件偏移(File off)。在链接之前,目标文件中的所有段的VMA都是0,因为虚拟空间还没有被分配,所以它们默认都为0。等到链接之后,可执行文件“ab”中的各个段都被分配到了相应的虚拟地址。“.text”段被分配到了地址0x08048094,大小为0x72字节,为a.o和b.o的“.text”大小之和;“.data”段从地址0x08049108开始,大小为4字节,为a.o和b.o的“.data”大小之和。整个链接过程前后,目标文件各段的分配、程序虚拟地址如下图所示:

在这里插入图片描述

可以看到链接器要将可执行文件“ab”的“.text”分配到0x08048094、将“.data”分配0x08049108。这涉及操作系统的进程虚拟地址空间的分配规则,在Linux 下,ELF可执行文件默认从地址0x08048000开始分配。

符号地址的确定

当空间地址分配完成后,链接器开始计算各个符号的虚拟地址,这时“main”、“shared”和“swap”的地址也已经是确定的了,链接器需要给每个符号加上一个偏移量,使它们能够调整到正确的虚拟地址。从前面“objdump”的输出看到,“main”位于“a.o”的“.text”段的最开始,也就是偏移为0,所以“main”这个符号在最终的输出文件中的地址应该是0x08048094+ 0,即0x08048094;而“swap”这个符号位于b.o的“.text”开始,偏移量也就是“a.o”的“.text”的大小0x00000034,所以“swap”这个符号在最终的输出文件中的地址应该是0x08048094+ 0x00000034,即0x080480c8;shared位于“.data”段的最开始,偏移量为0,所以“swap”这个符号在最终的输出文件中的地址应该是0x08048108+ 0,即0x08048108。所以链接器在更新全局符号表的符号地址以后,各个符号的最终地址如图所示:

在这里插入图片描述

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

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

相关文章

从Mybatis到Mybatis-Plus学习

从Mybatis到Mybatis-PlusMybatis的入门Mybatis的配置解析核心配置文件分页配置注解开发mybatis的执行流程多对一一对多动态SQLmybatis 的缓存Mybatis-plus快速入门mybatis-plus的框架结构图分页查询和删除执行SQL分析打印条件构造器Wrapper代码生成器Mybatis的入门 环境&#…

io复用函数的使用

目录 一、概念 二、使用 1.select系统调用 代码实现 前言: 一般多客户端在和服务器通信时,服务器在执行recv时会先阻塞,然后按照顺序依次处理客户端,无论客户端有无数据都会被处理,这样大大降低了执行效率。此时就引…

代理 模式

代理模式 Proxy Pattern 为其他对象提供一个代理以控制对这个对象的访问 可以详细控制访问某个(某类)对象的方法,在调用这个方法前做前置处理,调用这个方法后做后置处理。 静态代理 直接写死的代码的代理逻辑 动态代理 动态…

12.2、后渗透测试--令牌窃取

攻击机kali:192.168.11.106靶机windows server 2008 R2:192.168.11.134(包含ms17_010漏洞)一、令牌简介与原理 令牌(Token) 就是系统的临时密钥,相当于账户名和密码,用来决定是否允许这次请求和判断这次请求…

二进制搭建k8s——部署node节点

上篇:二进制搭建k8s——部署etcd集群和单master 二进制搭建k8s——部署node节点二进制搭建k8s——部署node节点环境部署node节点部署网络组件方法一:部署Flannel方法二:部署 CalicoCNI网络插件介绍Kubernetes的三种网络K8S 中 Pod 网络通信&a…

浅浅讲解下Linux内存管理之CMA

说明: Kernel版本:4.14ARM64处理器,Contex-A53,双核使用工具:Source Insight 3.5, Visio 1. 概述 Contiguous Memory Allocator, CMA,连续内存分配器,用于分配连续的大块内存。CMA…

c语言内存和文件处理有关知识

内存 分配内存的函数calloc&#xff0c;malloc 定义于头文件 <stdlib.h>功能malloc分配内存(函数)calloc分配并清零内存(函数)realloc扩充之前分配的内存块(函数)free归还还之前分配的内存(函数)aligned_alloc(C11)分配对齐的内存(函数) 函数原型 void *malloc(unsigne…

Java基础之Collection的ArrayList

Java基础之Collection的ArrayList一、add()与addAll()二、remove()三、trimToSize()1、案例一、add()与addAll() 跟C 的vector不同&#xff0c;ArrayList没有push_back()方法&#xff0c;对应的方法是add(E e)&#xff0c;ArrayList也没有insert()方法&#xff0c;对应的方法是…

Oracle---初学篇

Oracle初学篇 Oracle的启动&#xff0c;监听&#xff0c;用户 文章目录Oracle初学篇Oracle的启动Oracle的监听监听服务的主要文件1.listener.ora2.tnsnames.ora3.sqlnet.oraOracle用户Oracle安装成功后默认的三个用户创建用户Oracle的启动 之前写了关于如何在CentOS7上搭建Ora…

2021年全国研究生数学建模竞赛华为杯D题抗乳腺癌候选药物的优化建模求解全过程文档及程序

2021年全国研究生数学建模竞赛华为杯 D题 抗乳腺癌候选药物的优化建模 原题再现&#xff1a; 一、背景介绍   乳腺癌是目前世界上最常见&#xff0c;致死率较高的癌症之一。乳腺癌的发展与雌激素受体密切相关&#xff0c;有研究发现&#xff0c;雌激素受体α亚型&#xff0…

LeetCode 0547. 省份数量:图的连通分量

【LetMeFly】547.省份数量 力扣题目链接&#xff1a;https://leetcode.cn/problems/number-of-provinces/ 有 n 个城市&#xff0c;其中一些彼此相连&#xff0c;另一些没有相连。如果城市 a 与城市 b 直接相连&#xff0c;且城市 b 与城市 c 直接相连&#xff0c;那么城市 a …

Windows文件夹开启大小写敏感

Windows 的文件系统的文件名&#xff0c;是大小写不敏感的&#xff0c;也就是你的文件名是 a.txt 或者 A.txt&#xff0c;在 Windows 中都是一视同仁&#xff0c;认为是同一个文件。 自从 Windows 10 引入 Linux 子系统&#xff08;WSL&#xff09;后&#xff0c;有越来越多开…

JAVA毕业设计——基于ssm的汽车租赁管理系统 (源代码+数据库)

代码地址 https://github.com/ynwynw/carRental-public 毕业设计所有选题地址 https://github.com/ynwynw/allProject 基于Springboot的汽车租赁管理系统 (源代码数据库)601 一、系统介绍 汽车租赁系统总共分为两个大的模块&#xff0c;分别是系统模块和业务模块。其中系统模…

基于混沌原子搜索优化的电力系统(HPS)负载频率自动控制(ALFC)(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

Spring Security 中的四种权限控制方式

Spring Security 中对于权限控制默认已经提供了很多了&#xff0c;但是&#xff0c;一个优秀的框架必须具备良好的扩展性&#xff0c;恰好&#xff0c;Spring Security 的扩展性就非常棒&#xff0c;我们既可以使用 Spring Security 提供的方式做授权&#xff0c;也可以自定义授…

如何实现外网访问API接口

Application Programming Interface 缩写为API&#xff0c;中文翻译为“应用程序接口”&#xff0c;是一些预先定义的函数&#xff0c;或指软件系统不同组成部分衔接的约定。目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力&#xff0c;而又无需访问源码&…

TVS管开关电源防护应用及电源防护元件的品类

瞬态抑制二极管简称TVS管。其作用原理是能够在极短的时间内承受反向电压的冲击&#xff0c;使得两极之间的电压钳位在特定电压水平上&#xff0c;有效避免了对后面电路的冲击&#xff0c;从而保护了被保护电子线路中的精密元件不受其损害。 瞬态抑制二极管TVS的钳位响应速度为为…

pytest + yaml 框架 -7.用例分层机制

前言 当我们测试流程类的接口&#xff0c;需反复去调用同一个接口&#xff0c;就会想到复用API&#xff0c;在代码里面可以写成函数去调用。 那么在yaml 文件中&#xff0c;我们可以把单个API写到一个yaml 文件&#xff0c;测试用例去调用导入API。 pip 安装插件 pip instal…

电子产品设计的流程有哪些

电子产品设计过程是指导工业外观设计的具体环节&#xff0c;主要包括产品市场需求分析、产品设计、产品原型设计、生产测试设计、大规模生产等方法和步骤。 一、电子产品设计流程是什么? 1.产品市场需求分析是电子产品设计成功的第一步&#xff0c;也是非常重要的一步。开发者…

JavaSE(数组)

1. 数组 数组创建及初始化 总结&#xff1a; 三种写法包括了动态初始化和静态初始化&#xff0c;其中省略格式不能再省略&#xff08;拆分&#xff09;&#xff1b;没有初始化时&#xff08;默认值为基类类型对应的默认值&#xff09;其中引用类型的默认值为null 三种写法 1…