为何C语言的函数调用要用到堆栈,而汇编却不需要自定义栈

news/2024/4/27 16:38:35/文章来源:https://blog.csdn.net/TyearLin/article/details/130354317

一  ≠ 汇编不需要堆栈

汇编中一般不初始化,也就是直接使用系统的堆栈而已,自己定义堆栈还是要初始化的。

之前看了很多关于uboot的分析,其中就有说要为C语言的运行,准备好堆栈。

而自己在Uboot的start.S汇编代码中,关于系统初始化,也看到有堆栈指针初始化这个动作。但是,从来只是看到有人说系统初始化要初始化堆栈,即正确给堆栈指针sp赋值,但是却从来没有看到有人解释,为何要初始化堆栈。所以,接下来的内容,就是经过一定的探究,试图来解释一下,为何要初始化堆栈,即:

1 为何C语言的函数调用要用到堆栈,而汇编却不需要初始化堆栈

差不多可以这样理解
从纯粹的 C的语法上来说,是没有办法初始化堆栈的。
例如 标准C 语言,就没有提供直接操作硬件的支持

汇编写的程序运行时也需要栈,操作系统加载可执行文件后每个线程都有自己的局部栈。理论上完全不用栈也是可以的,只要有数据区用于保存临时数据就可以。

JAVA 字节码在JVM上执行 标准的JVM线程模型中 操作数,局部变量,动态链接 返回地址 等也都是放在私有线程栈中 ,上层语言必然是基于底层架构。所以很多原因甚至系统都有很多相似之处 。

2 解堆栈的作用。

总的来说,堆栈的作用就是:保存现场/上下文,传递参数。

保存现场,也叫保存上下文。

侠义上,上下文是针对中断来体现其具体含义的,在内核设计者的眼中,当一个任务在中断时,CPU会去执行中断对应的任务。中断结束后,再执行之前的task时,原有任务的相关数据(在处理原任务所需要的数据)需要保存下来,否则无法继续执行原有任务。如果把相关数据记录到一个变量里。那这个变量就可以称为原task的上下文了。

ARM架构中   

一般情况下,一个程序编译后本质上都是至少由 bss段、data段、text段三个组成的

437a06a7cf7ad33913da636bf377bf12.png

 

汇编

.bss段:(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。BSS是英文Block Started by Symbol的简称.bss段属于静态内存分配。
.data段 :数据段(data segment)通常是指用来存放程序中 已初始化 的 全局变量 的一块内存区域。数据段属于静态内存分配。
.text/.code段: 代码段(code segment/text segment)通常是指用来存放 程序执行代码 的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于 只读 , 某些架构也允许代码段为可写,即允许修改程序。在代码段中,也有可能包含一些 只读的常数变量 ,例如字符串常量等。程序段为程序代码在内存中的映射.一个程序可以在内存中多有个副本.
在单片机上RAM存放data段,bss段,堆栈段;ROM(EPROM,EEPROM,Flash等非易失性存储设备)存放代码,只读数据段。
对单片机编程后,程序的代码段.data段.bss段.rodata段等都存放在Flash中。当单片机上电后,初始化汇编代码将data段,bss段,复制到RAM中,并建立好堆栈,开始调用程序的main函数。

c/c++

一个由C/C++编译的程序占用的内存分为以下几个部分
1>栈区(stack)——由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
2>堆区(heap)——一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。
3>全局区(静态区)(static)——全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系统释放
4>文字常量区——常量字符串就是放在这里的(不可修改)。 程序结束后由系统释放
5>程序代码区——存放函数体的二进制代码。
其中堆区和栈区存放在RAM中,而全局区、文字常量区、程序代码区存放在ROM(Flash)中。

 

3 如何保存现场及恢复

1 汇编

保存寄存器的值,一般用的是push指令,将对应的某些寄存器的值,一个个放到堆栈中,把对应的值压入到堆栈里面,即所谓的压栈

然后待被调用的子函数执行完毕的时候,再调用pop,把堆栈中的一个个的值,赋值给对应的那些你刚开始压栈时用到的寄存器,把对应的值从堆栈中弹出去,即所谓的出栈

其中保存的寄存器中,也包括lr的值(因为用bl指令进行跳转的话,那么之前的pc的值是存在lr中的),然后在子程序执行完毕的时候,再把堆栈中的lr的值pop出来,赋值给pc,这样就实现了子函数的正确的返回。

2 C语言

c进行函数调用的时候,常常会传递给被调用的函数一些参数,对于这些C语言级别的参数,被编译器翻译成汇编语言的时候,就要找个地方存放一下,并且让被调用的函数能够访问,否则就没发实现传递参数了。对于找个地方放一下,分两种情况。

一种情况是,本身传递的参数就很少,就可以通过寄存器传送参数。

因为在前面的保存现场的动作中,已经保存好了对应的寄存器的值,那么此时,这些寄存器就是空闲的,可以供我们使用的了,那就可以放参数,而参数少的情况下,就足够存放参数了,比如参数有2个,那么就用r0和r1存放即可。(关于参数1和参数2,具体哪个放在r0,哪个放在r1,就是和APCS中的“在函数调用之间传递/返回参数”相关了,APCS中会有详细的约定。感兴趣的自己去研究。)

但是如果参数太多,寄存器不够用,那么就得把多余的参数堆栈中了。

即,可以用堆栈来传递所有的或寄存器放不下的那些多余的参数。


 

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

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

相关文章

一文详细介绍查看和启用nginx日志(access.log和error.log),nginx错误日志的安全级别,自定义访问日志中的格式

文章目录 1. 文章引言2. Nginx访问日志(access.log)2.1 简述访问日志2.2 启用Nginx访问日志2.3 自定义访问日志中的格式 3. Nginx错误日志(error.log)3.1 简述错误日志3.2 启用错误日志3.3 Nginx错误日志的安全级别 4. 文末总结 1. 文章引言 我们在实际工作中,经常使…

学习spark笔记

✨ 学习 Spark 和 Scala 一 ​ 🐦Spark 算子 spark常用算子详解(小部分算子使用效果与描述不同) Spark常用的算子以及Scala函数总结 Spark常用Transformations算子(二) Transformation 算子(懒算子):不会提交spark作业&#…

SLAM论文速递:SLAM—— 流融合:基于光流的动态稠密RGB-D SLAM—4.25(2)

论文信息 题目: FlowFusion:Dynamic Dense RGB-D SLAM Based on Optical Flow 流融合:基于光流的动态稠密RGB-D SLAM论文地址: https://arxiv.org/pdf/2003.05102.pdf发表期刊: 2020 IEEE International Conference on Robotics and Automa…

flex布局属性详解

Flex布局 flex-directionflex-wrapflex-flowjustify-contentalign-itemsalign-content其他orderflexalign-self 含义:Flex是Flexible Box的缩写,意为”弹性布局”,用来为盒状模型提供最大的灵活性。 flex-direction flex-direction属性决定主轴的方向&…

危险区域闯入识别系统 yolov8

危险区域闯入识别系统通过YOLOv8网络模型技术,危险区域闯入识别系统对现场画面中发现有人违规闯入禁区,系统立即抓拍告警同步回传后台。YOLOv8 提供了一个全新的 SOTA 模型,包括 P5 640 和 P6 1280 分辨率的目标检测网络和基于 YOLACT 的实例…

Model-Contrastive Federated Learning 论文解读(CVPR 2021)

Model-Contrastive Federated Learning 论文解读 对比学习SimCLR 对比学习的基本想法是同类相聚,异类相离 从不同的图像获得的表征应该相互远离,从相同的图像获得的表征应该彼此靠近 具体框架: T随机数据增强模块:随机裁剪然…

光波导相控阵技术

在简述电光效应和热光效应的基础上综述了国内外光波导相控阵技术研究进展,包括一维和二维光波导相控阵的技术途径、结构特点和性能指标,给出了光波导相控阵的优势以及在激光雷达、成像等领域的应用前景。结果表明,光波导相控阵技术正向着大扫…

JavaScript Debugger 调试断点模式

在代码中加入debugger,相当于断点停顿,可用于查看变量传递情况,比如:Vue组件中生命周期onLoad(options) ,在上一页面进入下一页面后,传递进来的参数值。 备注 :options 参数为字符串&#xff0…

从需求分析到上线发布,一步步带你开发收废品小程序

在如今的环保和可持续性的大趋势下,废品回收已经成为了人们日常生活中不可或缺的一部分。收废品小程序的开发可以帮助人们更方便地找到回收废品的地点,并有效减少废品对环境造成的污染。因此,我们的收废品小程序需要满足以下需求:…

2023年电信推出新套餐:月租19元=135G流量+长期套餐+无合约期!

在三大运营商推出的流量卡当中,电信可以说是性价比最高的一个,相对于其他两家运营商,完全符合我们低月租,大流量的要求,所以,今天小编介绍的还是电信流量卡。 在这里说一下,小编推荐的卡都是免…

中国制造再击败一家海外企业,彻底取得垄断地位

中国制造已在13个行业取得领先优势,凸显出中国制造的快速崛起,日前中国制造又在一个行业彻底击败海外同行,再次证明了中国制造的实力。 一、海外企业承认失败 提前LGD宣布它位于广州的8.5代液晶面板生产线停产,预计该项目将出售给…

Linux命令rsync增量同步目录下的文件

业务场景描述 最近遇到一个问题,需要编写相应的Linux命令,增量同步/var/mysql里的所有文件到另外一个目录/opt/mysql,但是里面相关的日志文件xx.log是不同步的,这个场景,可以使用rsync来实现 什么是rsync命令&#x…

6、什么是类型断言?

虽然 TypeScript 很强大,但有时还不如我们了解一个值的类型方便,这时候我们更希望 TypeScript 不要帮我们进行类型检查,而是交给我们自己来,所以就用到了类型断言。类型断言有点像是一种类型转换,它把某个值强行指定为…

当,Kotlin Flow与Channel相逢

前言 之前的文章已经分析了Flow的相关原理与简单使用,Flow之所以用起来香,Flow便捷的操作符功不可没,而想要熟练使用更复杂的操作符,那么需要厘清Flow和Channel的关系。 本篇文章构成: 1. Flow与Channel 对比 1.1 Fl…

论文实验1、安装tensorflow运行节点嵌入相关方法

还是官方的教程好使 使用 pip 安装 TensorFlow 只有三步 1.安装python,版本太高不行,在推荐版本里选最高的。 2.安装python虚拟环境venv python -m venv --system-site-packages .\venv .\venv\Scripts\activate 3.在虚拟环境里装tensorflow pip…

开发人员应考虑使用 Edge浏览器的 8 个理由

1.无限访问ChatGPT 这是正确的。您可以通过 Bing 访问 GPT-4。但与 2021 年后没有数据的 ChatGPT 不同,必应通过从自己的搜索引擎中提取最新数据来对其进行补偿。 首先,点击Edge 浏览器左上角的Bing 小图标 Bing 具有三个选项卡:Chat、Compo…

VSCode连接远程服务器调试代码详细流程

文章目录 1.远程连接服务器2. 打开项目文件目录3. 配置调试环境 在研究人工智能项目时,很多时候本地机器性能不够,只能把代码拉倒服务器上,然后利用服务器资源来运行代码。遇到问题时需要调试,本文详细介绍利用VScode来调试远程服…

DAB-Deformable-DETR代码学习记录之模型构建

DAB-DETR的作者在Deformable-DETR基础上,将DAB-DETR的思想融入到了Deformable-DETR中,取得了不错的成绩。今天博主通过源码来学习下DAB-Deformable-DETR模型。 首先我么看下Deformable的创新之处: Deformable-DETR创新 多尺度融合 首先便是…

layui 表格中嵌入下拉框被遮挡

1、代码 单元格样式: * 设置下拉框的高度与表格单元相同 */.layui-table-cell {width: 100%;height: 100%;border: 1px;border-color: #F2F2F2;} 表格初始化后的回调: done: function (res, curr, count) {$(".layui-table-body, .layui-tabl…

MC9S12G128开发板—实现按键发送CAN报文指示小车移动功能

实验环境:MC9S12G128开发板 基本功能:控制开发板上的按键,模拟车辆移动的上下左右四个方位,通过can通信告诉上位机界面,车辆轨迹的移动方位。 1. 1939报文发送的示例代码 MC9S12G128开发板1939协议发送can报文数据的…