什么是ARM中的SP(堆栈)和LR?
LR是用于保存函数调用的返回地址的link register。
SP是堆栈指针。堆栈通常用于在函数调用中保存”automatic”变量和上下文/参数。从概念上讲,您可以将”stack”视为您”pile”您的数据的地方。您将”stacking”保留在一个数据之上,堆栈指针告诉您”high”的数据是”stack”。您可以从”stack”的”top”中删除数据并缩短。
从ARM架构参考:
SP, the Stack Pointer
Register R13 is used as a pointer to the active stack.
In Thumb code, most instructions cannot access SP. The only instructions that can access SP are those designed to use SP as a stack pointer. The use of SP for any purpose other than as a stack pointer is deprecated. Note Using SP for any purpose other than as a stack pointer is likely to break the requirements of operating systems, debuggers, and other software systems, causing them to malfunction.
LR, the Link Register
Register R14 is used to store the return address from a subroutine. At other times, LR can be used for other purposes.
When a BL or BLX instruction performs a subroutine call, LR is set to the subroutine return address. To perform a subroutine return, copy LR back to the program counter. This is typically done in one of two ways, after entering the subroutine with a BL or BLX instruction:
• Return with a BX LR instruction.
• On subroutine entry, store LR to the stack with an instruction of the form: PUSH {,LR} and use a matching instruction to return: POP {,PC} …
This link gives an example of a trivial subroutine.
次佳解决方案
SP是堆栈寄存器,用于键入r13的快捷方式。 LR是r14的快捷方式。 PC是程序计数器,用于输入r15的快捷键。
当执行一个调用,称为分支链接指令bl时,返回地址放在r14(链接寄存器)中。程序计数器pc更改为您要分支的地址。
传统的ARM内核中有几个堆栈指针(cortex-m系列是一个例外),当您打中断时,例如使用与前台运行时不同的堆栈,您不必更改代码,只需使用sp或r13正常情况下,硬件已经为您完成了开关,并在解码指令时使用正确的开关。
传统的ARM指令集(而不是Thump指令集)使您可以自由使用从低地址到更高地址的堆栈,或者从高地址到低地址的增长。编译器和大多数人将堆栈指针设置为高电平,并将其从高地址下降到较低的地址。例如,例如,您可以将ram从0x20000000设置为0x20008000,您可以设置链接描述文件来构建程序来运行/使用0x20000000,并将启动代码中的堆栈指针设置为0x20008000,至少要将系统/用户堆栈指针分开其他堆栈的内存,如果你需要/使用它们。
堆栈只是 memory 。处理器通常具有基于PC的特殊存储器读/写指令,一些是基于堆栈的。堆栈的最小值通常被称为push和pop,但不一定是(和传统的arm指令一样)。
如果你去http://github.com/lsasim我创建了一个教学处理器,并有一个汇编语言教程。在那里我会经历关于堆栈的讨论。它不是一个ARM处理器,但故事是一样的,它应该直接转换到你想要在ARM或大多数其他处理器上理解。
例如,您的程序中需要20个变量,但只有16个寄存器减去至少三个(sp,lr,pc),这些是特殊用途。你将不得不将一些变量保留在ram中。让我们说r5拥有一个你经常使用的变量,你不想保持在ram中,但是有一段代码,你真的需要另一个注册表来做某事,r5没有被使用,你可以保存r5堆栈以最小的努力,而您重用r5的其他东西,然后,很容易,恢复它。
传统(不一定都回到起初)ARM语法:
...
stmdb r13!,{r5}
...temporarily use r5 for something else...
ldmia r13!,{r15}
..
stm是存储多个,一次可以保存多个寄存器,直到所有这些都在一个指令中。
db表示之前递减,这是从高地址到较低地址的向下移动堆栈。
您可以使用r13或sp来指示堆栈指针。该特定指令不限于堆栈操作,可用于其他操作。
的!意味着在完成后用新地址更新r13寄存器,这里再次使用stm可以用于non-stack操作,因此您可能不想更改基地址寄存器,离开!在这种情况下。
然后在括号{}中列出要保存的寄存器,以逗号分隔。
ldmia是相反的,ldm表示加载多个。 ia表示递增,其余与stm相同
所以如果你的堆栈指针在0x20008000,当你打到stmdb指令看到,因为列表中有一个32位寄存器,它将在它使用它之前减少r13中的值,所以0x20007FFC然后它在存储器中写入r5到0x20007FFC,并保存值0x137FFC在r13。后来,假设你没有错误,当你得到ldmia指令r13有0x20007FFC在其中有一个单一的注册表在列表r5。所以它在0x20007FFC读取内存将该值放在r5中,ia表示增量后,0x20007FFC将一个寄存器大小增加到0x20008000,而!意味着将该号码写入r13以完成指令。
你为什么要使用堆栈而不是固定的内存位置?那么上面的美妙之处在于,当您运行该代码或0x20002000或其他任何代码仍然可以运行时,r13可以是0x20007654,如果您在循环中使用该代码,或者在循环中使用该代码,或者对于每个级别您递交的递归保存r5的新副本,您可能有30个保存的副本,具体取决于您在该循环中的位置。并且当它展开时,将所有副本放回所需的位置。单个固定内存位置不起作用。这将直接转换为C代码作为示例:
void myfun ( void )
{
int somedata;
}
在这样的C程序中,变量somedata存在于堆栈中,如果您递归调用myfun,则根据递归的深度,您将有多个副本的somedata值。此外,由于该变量仅在函数内部使用,并且不需要其他位置,那么您可能不想在程序的生命周期内为该变量刻录一定量的系统内存,只需要在该函数中使用这些字节,并释放该内存不在那个功能。这就是堆栈的用途。
在堆栈中找不到全局变量
回去…
说你想实现和调用这个函数,你会在调用myfun函数时有一些代码/函数。 myfun函数希望使用r5和r6,当它正在操作的东西,但它不想垃圾的任何人称它是使用r5和r6这样的持续时间的 myfun()你想要保存在堆栈上的这些寄存器。同样,如果您查看分支链接指令(b1)和链接寄存器lr(r14),则只有一个链接寄存器,如果从函数调用函数,则需要在每次调用时保存链接寄存器,否则您无法返回。
...
bl myfun
<--- the return from my fun returns here
... myfun:
stmdb sp!,{r5,r6,lr}
sub sp,#4 <--- make room for the somedata variable
...
some code here that uses r5 and r6
bl more_fun <-- this modifies lr, if we didnt save lr we wouldnt be able to return from myfun
<---- more_fun() returns here
...
add sp,#4 <-- take back the stack memory we allocated for the somedata variable
ldmia sp!,{r5,r6,lr}
mov pc,lr <---- return to whomever called myfun.
所以希望你可以看到堆栈的使用和链接寄存器。其他处理器以不同的方式做同样的事情。例如有些将把返回值放在堆栈上,当你执行返回函数时,它通过从栈中拉一个值来知道在哪里返回。编译器C /C++等通常会有一个”calling convention”或应用程序接口(ABI和EABI是ARM定义的名称)。如果每个函数遵循调用约定,则将参数传递给在正确的寄存器或堆栈中被调用的函数。并且每个函数遵循规则,关于什么寄存器不必保留其内容和什么寄存器来保存内容,那么你可以使用函数调用函数调用函数,并执行递归和各种事情,只要堆栈不会太深,以至于它运行到用于全局变量和堆的内存中,所以您可以调用函数并从整个日期返回。 myfun的上述实现与编译器生成的内容非常相似。
ARM现在有很多核心和一些指令集,cortex-m系列的工作原理有所不同,只要没有一堆模式和不同的堆栈指针。并且在拇指模式下执行拇指指令时,您可以使用推送和弹出指令,这些指令不会让您自由使用任何类似stm的寄存器,它只使用r13(sp),而且您无法仅将所有寄存器保存在其特定子集中。流行的ARM组装人员允许您使用
push {r5,r6}
...
pop {r5,r6}
ARM代码以及拇指代码。对于arm代码,它编码适当的stmdb和ldmia。 (在缩略图模式下,您也不必选择使用db的时间和位置,之前递减,ia,后增加)。
不,您绝对不必使用相同的寄存器,您不必配对相同数量的寄存器。
push {r5,r6,r7}
...
pop {r2,r3}
...
pop {r1}
假设在这些指令之间没有其他堆栈指针修改,如果你记得sp将被递减12个字节的推送,我们说从0x1000到0x0FF4,r5将被写入0xFF4,r6到0xFF8和r7到0xFFC堆栈指针将变为0x0FF4。第一个pop将取值为0x0FF4,并将其放在r2中,然后将值置于0x0FF8,并将其置于r3中,堆栈指针将获取值0x0FFC。稍后最后一个pop,sp为0x0FFC,读取的值为r1,然后堆栈指针的值为0x1000,在那里开始。
ARM ARM,ARM架构参考手册(infocenter.arm.com,参考手册,找到适用于ARMv5并下载的手册,这是ARM ARM与ARM和Thumb指令的传统ARM),包含ldm和stm ARM的伪代码关于这些如何使用的完整图片。同样,整本书都是关于ARM和如何编程的。在程序员模型章节前面将介绍所有模式下的所有寄存器等。
如果您正在编程ARM处理器,您应该首先确定(芯片厂商应该告诉您,ARM不会使芯片使芯片厂商的芯片成为芯片厂商的核心)。然后去arm站,找到那个家族的ARM ARM,找到特定内核的TRM(技术参考手册),包括修正版本(如果供应商提供的)(r2p0表示版本2.0(二点零,2p0)),甚至如果存在较新的转速,请使用与设计中使用的供应商所使用的手册。不是每个核心都支持每个指令或模式,TRM告诉您ARM ARM支持的模式和指令,总结了核心所处的整个处理器系列的功能。请注意,ARM7TDMI不是ARMv7,而是ARMv7 ARM9不是ARMv9。 ARMvNUMBER是家族名称ARM7,ARM11没有v是核心名称。较新的内核具有像Cortex和mpcore这样的名称,而不是ARMNUMBER的东西,这减少了混乱。当然,他们不得不通过制造一个非常不同的系列的ARMv7-m(cortex-MNUMBER)和ARMv7-a(Cortex-ANUMBER)来增加混乱,一个用于重负载,台式机,笔记本电脑等,另一个是微控制器,时钟并在咖啡壶和类似的东西上闪烁的灯光。谷歌beagleboard(Cortex-A)和stm32值行发现板(Cortex-M)得到感觉的差异。或者甚至使用多于千兆赫兹的多核的open-rd.org板,或者来自nvidia的更新的tegra 2,相同的交易超级定标器,多核,多吉赫兹。 cortex-m几乎没有制动100MHz的屏障,并且以千字节测量的内存,尽管如果你想要一个cortex-a的地方,它可能会运行一个电池几个月。
对于很长的帖子很抱歉,希望它是有用的。
什么是ARM中的SP(堆栈)和LR?的更多相关文章
- ARM中的汇编指令
Arm指令,32位的指令集,一共有16条的基本指令,每条指令都可以按条件执行, 指令都是32bit的,高四位是条件码[31:28], Thumb指令,16位的指令集,执行效率比arm指令集要低,但是节 ...
- ARM 中必须明白的几个概念
文章具体介绍了关于ARM的22个常用概念. 1.ARM中一些常见英文缩写解释 MSB:最高有效位: LSB:最低有效位: AHB:先进的高性能总线: VPB:连接片内外设功能的VLSI外设总线: EM ...
- 如何在ARM中创建Express Route
很早之前就想试试Azure的express route,但是一直没有找到合适的机会,正好有个客户需要上express route,所以最近先自己研究研究,防止在做poc的时候耗费更多时间,本次场景我们 ...
- 如何将已部署在ASM的资源迁移到ARM中
使用过Azure的读者都知道,Azure向客户提供了两个管理portal,一个是ASM,一个是ARM,虽然Azure官方没有宣布说淘汰ASM,两个portal可能会在很长的一段时间共存,但是考虑到AR ...
- ARM中的总线
ARM中的总线用于不同部件之间的通信.有两种不同类型的设备连接到总线:ARM处理器,它是总线的主设备,拥有对总线的仲裁权,可以通过同一总线主动发起数据传输请求:外围器件,是总线的从设备,在总线上是被动 ...
- java中堆和堆栈的区别
java中堆和堆栈的区别(一) 1.栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方.与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆. 2. 栈的优势是,存取 ...
- GCC 中的编译器堆栈保护技术
GCC 中的编译器堆栈保护技术 前几天看到的觉得不错得博客于是转发了,但这里我补充一下一些点. GCC通过栈保护选项-fstack-protector-all编译时额外添加两个符号,__stack_c ...
- [搬运] .NET Core 2.1中改进的堆栈信息
原文 : Stacktrace improvements in .NET Core 2.1 作者 : Ben Adams 译者 : 张很水 . NET Core 2.1 现在具有可读的异步堆栈信息!使 ...
- Android中的sp和wp指针
经常会在android的framework代码中发现sp<xxx>和wp<xxx>这样的指针,平时看的时候都把他当成一个普通的指针封装过掉了,这几天终于忍不住了,想深入了解一下 ...
- ARM 中可用性集使用的注意事项
Azure 目前有两种部署模型:经典部署模型 (ASM) 和资源管理器 (ARM).如果您之前使用过 ASM 模式下的可用性集,那么很可能在使用 ARM 模式下的可用性集时,会遇到一些问题或者疑惑.这 ...
随机推荐
- Ubuntu访问samba共享文件
Ubuntu访问samba共享文件 参考:https://www.cnblogs.com/Wolf-Dreams/p/11241198.html 做法 安装samba-client.cifs-util ...
- 基于cifar数据集合成含开集、闭集噪声的数据集
前言 噪声标签学习下的一个任务是:训练集上存在开集噪声和闭集噪声:然后在测试集上对闭集样本进行分类. 训练集中被加入的开集样本,会被均匀得打上闭集样本的标签充当开集噪声:而闭集噪声的设置与一般的噪声标 ...
- Gitlab的安装和使用
安装和配置必要的依赖项 yum install dnf sudo dnf install -y curl policycoreutils openssh-server #将SSH服务设置成开机自启动 ...
- MongoDB手稿
- Odoo17.0 基于企业微信的备用金和费用报销
前面讲过了企业微信的基础应用,现在我们来看一下如何借助企业微信的审批端能力结合odoo来实现企业中的两大常规业务流程备用金和费用报销. 企业微信端设置 我们这里使用的是企业微信的原生审批流程,因此我们 ...
- 面试官:Dubbo一次RPC调用会经过哪些环节?
大家好,我是三友~~ 今天继续探秘系列,扒一扒一次RPC请求在Dubbo中经历的核心流程. 本文是基于Dubbo3.x版本进行讲解 一个简单的Demo 这里还是老样子,为了保证文章的完整性和连贯性,方 ...
- 很好用的SSH工具FinalShell
上图片:1.远程连接Linux 2.Linux:CentOS 3.虚拟机:
- [oeasy]python0132_变量含义_meaning_声明_declaration_赋值_assignment
变量定义 回忆上次内容 上次回顾了一下历史 python 是如何从无到有的 看到 Guido 长期的坚持和努力 编程语言的基础都是变量声明 python是如何声明变量的呢? 变量 想要定义变量 ...
- [oeasy]python0094_视频游戏_双人网球_pong_atari_mos_6502_雅达利_米洛华
编码进化 回忆上次内容 上次 我们回顾了 微软之前的 比尔盖茨和保罗艾伦 mits 迎来的 是帮手 还是隐患? intel-8080 遇到了 mos-6502 底层硬件 驱动 游戏行业进化 不光是扑克 ...
- oeasy教您玩转 linux 010213 中文 fcitx
我们来回顾一下 上一部分我们都讲了什么? 管道 ls | cowsay 管道的符号是| 管道的作用是连接 原来应该输出到屏幕的内容 通过管道流到了另一个命令做为参数 这次是否可以让cow说出一些中文 ...