ARM汇编寄存器和常用指令详解

这篇具有很好参考价值的文章主要介绍了ARM汇编寄存器和常用指令详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

AAPCS关于ARM寄存器的定义

r14寄存器,汇编语言,汇编,arm开发

对于32位及其以下的ARM处理器来说,函数调用规则如下:

  1. 父函数与子函数的入口参数以此通过 R0~R3 这4个寄存器传递。 父函数在调用子函数前先将子函数入口参数存入 R0~R3 寄存器中,若只有一个入口参数则使用 R0 寄存器传递,若有2个入口参数则使用 R0 和 R1 寄存器传递,以此类推。。当超过4个参数时,其余的入口参数则以此压入当前栈通过栈传递。子函数运行时,其将根据自身参数个数从 R0~R3 或者栈中读取入口参数
  2. 子函数通过 R0 寄存器将函数返回值传递给父函数。子函数返回时,将返回值存入 R0寄存器,当返回到父函数时,父函数读取 R0 寄存器就可以获得子函数的返回值。
  3. AAPCS规定,发生函数调用前由父函数备份 R0~R3 寄存器中有用的数据,若没有有用的数据则可以不处理,然后才能调用子函数,以防止父函数保存在 R0~R3 寄存器中有用的数据在子函数使用这些寄存器时被破坏。因此,无论父函数是否通过 R0~R3 寄存器向子函数传递入口参数,子函数都可以直接使用 R0~R3 寄存器,无需考虑改写 R0~R3 寄存器会破坏父函数存储在它们中的数值,子函数返回时也无需恢复 R0~R3 寄存器中的数值。
  4. R4~R11 寄存器为普通的通用寄存器。AAPCS规定,发生函数调用时,父函数无需对这些寄存器进行备份处理,若子函数需要使用这些寄存器,则由子函数负责备份(需要使用哪个就备份哪个),以防止破坏父函数保存在 R4~R11 寄存器中的数据。子函数返回父函数前需先恢复 R4~R11 寄存器中的数值(使用了哪个就恢复哪个),恢复到父函数调用子函数这一时刻的数值,然后再返回到父函数。
  5. R12 寄存器在某些版本的编译下另有他用,在函数调用时需要备份,它的用法等同于 R0~R3 寄存器。
  6. R13 寄存器时栈寄存器(SP),用来保护栈的当前指针,函数存储在栈中的数据就是通过这个寄存器来寻址的。函数返回时需要保证 SP 指向 调用 该函数时的栈地址。
  7. R14 寄存器时链接寄存器(LR),用来保存函数的返回地址。父函数调用子函数时,父函数会将调用子函数指令的下一条指令地址存入到 LR 寄存器中,当子函数返回时只需要跳转到 LR 寄存器里的地址就会返回父函数继续执行。父函数调用子函数将子函数返回地址存入 LR 寄存器前, LR 寄存器中保存的可能是父函数返回其上一级函数的地址或其他有用的数据,因此需要先备份 LR 寄存器然后才能调用子函数。
  8. R15 寄存器时程序寄存器(PC),正在执行的指令地址就存储在 PC 寄存器中,更改 PC 寄存器的数值就会执行这个数值所对应的地址中的指令。

寄存器

ARM内核有 18 个寄存器,包括 R0~R12,2个R13,R14,R15和 XPSR 寄存器。
其中 R13 寄存器又叫 SP 寄存器, R14 寄存器又叫 LR 寄存器, R15 寄存器也叫 PC 寄存器。

R0~R12 通用寄存器

这些通用寄存器用来临时存放数据,供处理器运行程序时使用。

其中某些寄存器在程序调用时还会有其他专用功能,
比如说 R0~R3 寄存器在程序调用时可以用来传递函数参数和返回值,R12 寄存器在某些情况下可以保存子程序调用的中间值。

R13-SP(Stack Pointer) 栈寄存器

在ARM内核中有 2个 SP,分别是 MSP 和 PSP,根据模式不同使用的 SP 寄存器不同,不能同时存在。

R14-LR(Link Register) 链接寄存器

用来保存跳转后返回的地址。
当发生函数调用时,LR 寄存器中保存着函数返回后需要执行的指令地址。

R15-PC(Program Counter) 程序计数器

存放的是当前所执行指令所在的地址。
当在C语言中调用函数或者产生跳转时,实际上就是通过改变PC寄存器的值实现的。

指令

数据计算指令: ADD ADR SUB
数据搬移指令: MOV LDR LDM STM PUSH POP
状态寄存器操作指令: MRS MSR
逻辑计算指令: AND
跳转指令: BX CBZ
软中断指令: SVC

ADD 加法指令

SUB 减法指令

MOV 数据搬移指令(复制)

LDR 将内存数据加载到寄存器

指令格式有两种:
LDR 目的寄存器,=常量
LDR 目的寄存器,[源寄存器]

第一种格式,是将常量值存入目的寄存器
第二种格式,是将源寄存器中的数据指向的内存地址中的数据存入目的寄存器

例:

LDR R0,=globalVariate ;globalVariate表示全局变量,变量名对应它的地址
LDR R3,[R0]

对应 C语言:

R0 = &globalVariate
R3 = *R0

LDM (LDR增强版,将多个连续数据存入到一组寄存器中)

根据对栈指针不同的操作方式可以有4中划分:
满栈(Full):栈指针指向栈顶最后一个入栈的位置,此时栈指针指向的栈空间是满的。
空栈(Empty):栈指针指向栈顶将要入栈的位置,此时栈指针指向的栈空间是没用过的,是空的。
递减栈(Descending):向栈内存储数据时栈指针向着内存地址减少的方向移动。
递增栈(Ascending):向栈内存储数据时栈指针向着内存地址增加的方向移动。
综合栈的空满和增减特性,栈可分为FD ED FA EA 这4种类型。

汇编指令提供了4种对栈的操作方式,分别是DB(Decrement Before)、DA(Decrement After)、IB(Increment Before)和IA(Increment After)。

  • DB意为栈指针先减少再操作
  • DA意为栈指针先操作再减少
  • IB意为栈指针先增加再操作
  • IA意为栈指针先操作再增加
    这4种操作方式都可以与 LDM 指令组合,形成 LDMDB、LDMDA、LDMIB和LDMIA 指令

LDM经常在栈操作中使用,有2中指令格式,以LDMIA为例:
LDMIA 源寄存器,{一组目的寄存器} ;目的寄存器之间可以用 ','分开,也可以用'-'表示一个范围的寄存器
LDMIA 源寄存器!,{一组目的寄存器}

第一种指令格式,从源寄存器指定的站地址开始,将栈中的一组数据存入到目的寄存器组中;
第二种指令格式,除了完成第一种指令格式功能外,还将源寄存器操作后指向的栈地址保存到源寄存器中。

例:
LDMIA R14,{R0-R3,R12}
LDMIA R1!,{R4-R7}

对应 C语言:

/* No.1 */
R0 = *R14
R1 = *(R14 + 4)  //32位,4字节
R2 = *(R14 + 8)  //32位,4字节
R3 = *(R14 + 12)  //32位,4字节
R12 = *(R14 + 16)  //32位,4字节
//操作完成,R14寄存器的数值仍不变

/* No.2 */
R4 = *R1
R5 = *(R1 + 4)  //32位,4字节
R6 = *(R1 + 8)  //32位,4字节
R7 = *(R1 + 12)  //32位,4字节
R1 = R1 + 16  //32位,4字节
//操作完成,将R1寄存器的数值更新为当前指向的栈地址

STM (将一组寄存器中的数据存入到栈中)

STM功能正好和LDM功能相反,同样,STM也有4种操作方式:STMDB、STMDA、STMIB和STMIA,分别与LDM对应
指令格式:
STMIA 目的寄存器,{一组源寄存器}
STMIA 目的寄存器!,{一组源寄存器}

例:
STMIA R13,{R0}

PUSH 压栈指令

指令格式:
PUSH {一组寄存器}

PUSH指令其实就是如下指令的简写:
STMDB SP!,{一组寄存器} ;先减少后操作

POP 出栈指令

POP指令可以将数据从栈中弹出到寄存器中
指令格式:
POP {一组寄存器}

PUSH指令其实就是如下指令的简写:
LDMIA SP!,{一组寄存器} ;先操作后增加

MRS

将 XPSR寄存器中的数据保存到通用寄存器中,格式为:
MRS 寄存器,XPSR

MSR

将通用寄存器中的数据保存到 XPSR寄存器,格式为:
MSR XPSR,寄存器

AND 与

将源寄存器中的数据和目的寄存器中的数据进行与操作,并将结果存入到目的寄存器中
指令格式:
AND 目的寄存器,源寄存器

BX 跳转

BX指令除了可以跳转到目的寄存器指向的地址外,还可以改变处理器运行的指令集
指令格式:
BX 寄存器

CBZ

CBZ指令判断 R0 寄存器中的数值是否为0,如果是0,则跳转到 __BACKUP_REG地址,其中__BACKUP_REG是一个地址常数
指令格式:
CBZ R0,__BACKUP_REG
即:

if(0 == R0) {
    goto __BACKUP_REG
}

SVC 软中断指令

指令格式:
SVC 立即数

例:
SVC #0

这条指令将产生一次软中断,并将立即数0存入指令中,这个立即数可以作为软中断号使用,软中断服务程序可以通过这个立即数区分不同的软中断服务。

汇编代码示例

父函数向子函数传6个参数,子函数将其参数之和返回,父函数将返回值 +7后的值,当做自己的返回值返回。

TestFunc1

TestFunc1

    ;需使用R4,R5寄存器,为避免破坏R4,R5寄存器中的数据,将其压栈
    PUSH {R4 - R5}
    LDR R0, =1     ;相当于 R0 = 1
    LDR R1, =2
    LDR R2, =3     ;R0~R3寄存器作为接口寄存器,可直接使用
    LDR R3, =4
    LDR R4, =5
    LDR R5, =6
    ;R4,R5寄存器压栈,是因为它们是作为第5,6个入口参数,需要栈传递
    ;R14(LR)寄存器压栈,是因为TestFunc2的返回地址将被存入LR寄存器,防止 LR 寄存器中现有数据破坏
    PUSH {R4 - R5, R14}
    BL TestFunct2      ;跳转到 TestFunc2函数
    ADD R0, #7      ;TestFunc2函数的返回值保存在R0寄存器,将其 +7
    ;恢复进入TestFunt1函数现场
    ;将 SP指针向栈顶方向移动 8个字节,跳过原来存入栈中的2个入口参数
    ;此时 SP指针指向的栈中存放的是调用TestFunc2函数前存入的 LR寄存器
    ADD SP, #8
    POP {R14}      ;弹出 LR寄存器,将其恢复到进入 TestFunc1函数前的数值
    POP {R4 - R5}  ;弹出 R4,R5寄存器,将其恢复到进入 TestFunc1函数前的数值
    BX R14     ;函数执行完毕,此时 R14保存的是TestFunc1函数的返回地址

TestFunc2

TestFunc2

    ADD R0, R1
    ADD R0, R2
    ADD R0, R3
    POP {R1, R2}  ;从栈中取出第5,6参数,将其值赋给R1,R2寄存器
    ADD R0, R1
    ADD R0, R2
    SUB SP, #8   ;POP时移动栈指针,现在恢复到进入此函数之前栈指针指向
    BX R14

C语言原型

char TestFunc1() {
    return TestFunc2(1, 2, 3, 4, 5, 6) + 7;
}

char TestFunc2(char p1, char p2, char p3, char p4, char p5, char p6) {
    return p1 + p2 + p3 + p4 + p5 + p6;
}

本文内容为阅读《嵌入式操作系统内核调度-底层开发者手册》笔记,如有侵权,请联系删除。文章来源地址https://www.toymoban.com/news/detail-779020.html

到了这里,关于ARM汇编寄存器和常用指令详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • FANUC机器人的位置寄存器及运算指令详解

    FANUC机器人的位置寄存器及运算指令详解 在FANUC机器人的嵌入式编程中,位置寄存器和运算指令起着至关重要的作用。位置寄存器用于存储机器人的位置和姿态信息,而运算指令则允许对这些位置寄存器进行数学和逻辑运算,从而实现复杂的机器人运动控制和路径规划。本文

    2024年02月02日
    浏览(59)
  • 嵌入式中详解 ARM 几个常见的寄存器方法

    大家好,今天来聊聊对于ARM几个特殊寄存器的理解,FP、SP和LR。 1、介绍 FP:栈顶指针,指向一个栈帧的顶部,当函数发生跳转时,会记录当时的栈的起始位置。 SP:栈指针(也称为栈底指针),指向栈当前的位置, LR:链接寄存器,保存函数返回的地址。 关于gcc就有一个关

    2024年02月20日
    浏览(42)
  • 【汇编中的寄存器分类与不同寄存器的用途】

    寄存器分类 在计算机体系结构中,8086CPU,寄存器可以分为以下几类: 1. 通用寄存器: 通用寄存器是用于存储数据和执行算术运算的寄存器。在 x86 架构中,这些通用寄存器通常包括 AX、BX、CX、DX、SI、DI、BP 和 SP。其中,AX、BX、CX 和 DX 寄存器可以分别作为累加器(accumulat

    2024年02月09日
    浏览(52)
  • 16位汇编通用寄存器

    1、输入命名debug,进入调试程序 2、r 命令显示寄存器 3、a命令输入汇编指令 4、t命令单步执行汇编指令 5.数据溢出后标志位NC 变为NY, 0变成1 最后A

    2023年04月11日
    浏览(63)
  • 通用寄存器-汇编复习(1)

    弄清寄存器表达,原理和配件及汇编实验验证。 8086cpu寄存器,字在寄存器存储 往期文章: 汇编语言基础-汇编复习(0)_luozhonghua2000的博客-CSDN博客 一个典型的 CPU(此处讨论的不是某一具体的 CPU)由运算器、控制器、寄存器(CPU工作原理)等器件构成,这些器件靠内部总线相连。前

    2024年02月07日
    浏览(50)
  • 【汇编语言】CS、IP寄存器

    理论:CPU执行何处的指令,取决于CS:IP 应用:程序员可以通过改变CS、IP中的内容,进行控制CPU即将要执行的目标指令; 问题:如何改变CS、IP中的值? 设想: 1、通过使用Debug中的R命令进行修改寄存器的值,例如rcs, rip。 结论:不可以。原因是:Debug是调试手段,并非程序方

    2024年02月08日
    浏览(49)
  • 汇编语言——第11章 标志寄存器

    目录 ​​​​​​​ 引言 11.1 ZF标志 11.2 PF标志 11.3 SF标志 检测点11.1 11.4 CF标志 11.5 OF标志 检测点11.2 11.6 abc指令 11.7 sbb指令 11.8 cmp指令 11.9 检测比较结果的条件转移指令 检测点11.3 11.10 DF标志和串传送指令 1、DF标志 2、串传送指令 11.11 pushf和popf 11.12 标志寄存器在Debug中的表示

    2024年02月07日
    浏览(42)
  • 8086汇编语言寄存器清零学习

    mov ax, 0      这样应清零了; sub ax, ax     这样也清了; xor ax, ax     这样也清零了;自己跟自己异或,异或是同则结果为0、不同结果为1;自己和自己,每一位都是相同的,异或后结果为0; and ax, 0     和0相与,这样也清零了; 自己写代码用 xor ax, ax ,用这个就对了,都

    2024年02月11日
    浏览(44)
  • 【汇编语言】栈区与SS:SP寄存器

    汇编语言 - 栈 栈是一块特殊的内存空间,本文涉及的CPU为8086CPU,所有与内存地址有关的数字皆为16进制 栈的运行规律 - 先进后出,后进先出 以下为入栈的过程: 以下是出栈的过程: 以上就是栈的运行机制,栈的入栈叫做push,出栈叫做pop 在8086CPU中,栈是一块特殊的内存空

    2023年04月08日
    浏览(65)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包