armv7-A系列1-核心寄存器以及使用

不论是对于哪种处理器而言,内部寄存器都是非常重要的一部分,它是处理器核心自带的内存,处理器核心的大部分操作都是在寄存器中完成,对于使用精简指令集的 arm 而言,所有操作都必须在寄存器中完成,不允许直接使用位于内存中的数据作为操作数,而需要先将内存数据加载到寄存器,在寄存器中操作完成再写回,这一点和复杂指令集系统是不同的,这更体现了内部寄存器的重要性,要了解 arm 处理器以及它的指令集,了解它的内部寄存器是第一步。

核心寄存器

armv7 架构总共 16 个 32 位核心寄存器,其中 r0~r12 是通用寄存器,r13~r15 是特殊寄存器:

  • r13 是 sp 寄存器,也是栈顶指针,保存着栈顶的位置。
  • r14 为链接寄存器 lr,用于保存返回地址,用于执行流的跳转返回。
  • r15 为程序计数器 pc,保存下一条取指指令的地址。

sp 寄存器保存栈顶的位置,栈是自高地址向低地址增长的,所以在 push 和 pop 的过程中,sp 指针会自动地更新,同时,在一些特殊的情况下,sp 指针也可以被用作通用寄存器保存临时数据,但是并不建议这么做。

lr 寄存器用于保存返回地址,但是程序的跳转往往伴随着嵌套,所以并不是所有的返回值都是由 lr 保存,通常在子程序的调用过程中会将返回地址 push 到栈中,lr 在中断或异常的场景下是必要的,同样的,lr也可以被当成通用寄存器使用,但是并不建议这么使用。

PC 是程序计数器,往 PC 中写入一个地址可以实现程序的跳转,也可以使用指令 B 或者 BL 实现程序跳转。因为 armv7 同时支持 arm 和 thumb 指令集,当处于 arm 指令集下时, PC 读取当前指令地址+8,当处于 thumb 指令集下时,PC 读取当前指令地址+4。arm 的处理器中引入了流水线技术,指令的执行需要经过取指、译码、执行三个步骤,这是经典的三级流水线结构,某些处理器甚至能达到 8 级流水线甚至更多,但是 PC 指针总是和前三个步骤相关。当前的指令为执行,下一条指令为译码,而下下条指令是取指,所以在 arm 指令集中,PC 的值是 当前指令地址 +8,表示取下下条指令,,而经典的 thumb 指令集为 16 位,所以是 +4。

bank 寄存器

在某些资料中,arm 的核心寄存器数量描述为 37 个(armv6),这是因为 arm 处理器中的 bank 寄存器。

bank 在 arm 处理器设计层面是一个常见的概念,意思是相同的外部接口对应内部不同的实现,这就像在程序中定义同名的全局变量和局部变量,尽管这两个变量的名称一样,但是对应不同的内存地址,在操作时自然互不相关。

armv7 中定义了 8 种处理器模式,对于每一种处理器模式,尽管操作的寄存器名称一样,其操作的寄存器实体可能是不一样的:

从上图可以看出,当从 user 模式进入到 svc 模式时,使用的是不同的 sp 和 lr 寄存器实体。

所以,如果以寄存器接口来算,寄存器为 16 个,如果以真正的寄存器实体来算,寄存器数量为 40 多个。

寄存器别名以及函数调用约定

在汇编程序中,就像寄存器 r13 可以使用 sp 来代替,为了方便使用以及功能区分,每一个寄存器都对应一个别名,且都对应一些默认的功能。

r0 ~ r3参数寄存器

r0 ~ r3 分别对应 a1 ~ a4,这四个寄存器专门用于函数的参数传递和返回值保存,在进行 C 语言的子程序调用时,r0 保存第一个参数、r1 保存第二个,以此类推,当函数参数多于 4 个时,剩下的参数将会被保存到栈上并传递到子程序中。当程序执行到子程序中,子程序会将寄存器中的参数压栈,值得一提的是:参数压栈的顺序是不定的,并不一定是从右往左压栈,这和编译器相关。

子程序返回时,会将返回值保存在 r0 寄存器中,当返回值大于一个寄存器宽度时,将会由多个寄存器保存,比如一个 8 字节的返回值会由 r0 和 r1 保存,当返回值的size大于四个寄存器宽度时,返回值将会保存在内存中,将对应的内存地址保存在 r0 中返回。

帧指针

在函数的调用过程中,通常使用栈帧结构,即 sp 指针总是指向程序的栈顶,同时设置一个帧指针来跟踪函数的调用,在每次函数调用时,帧指针都保存着当前函数在栈上的基地址,这样在函数返回时就可以非常方便地对栈上的内存资源进行回收(实际上并不是回收,而是直接将 sp 回退到帧指针处即可)。

事实上,在 arm 官方的手册中,帧指针是 r11,r11 的别名也是 fp(frame point),但是在实际的编译器实现中,从反汇编代码可以看出,r7 被作为帧指针而不是官方指定的 r11,博主也不清楚为什么会有这种理论与实现上的出入。但是事实确实是这样。

r9 寄存器

r9 寄存器的使用是由平台指定的,不同平台可能将它实现成不同的作用,大体会有几种实现:

  • 它可以在位置无关代码中保存内存的静态地址,别名为 SB(static base),在 Uboot 的实现中,r9 就被用来保存 global data 的起始地址。
  • 同时,它也可以被指定为线程寄存器,保存一些本地参数的地址,别名为 TR,thread register,在 cortex A 系列中,它通常被用作前者。r9 的另一个别名为 v6。

程序调用暂存器

r12 寄存器又名为 ip 寄存器,它可以作为程序内调用暂存寄存器,在 aapcs 的手册中有提到 ip 寄存器的作用:不论是 arm 还是 thumb 指令集中,bl 指令都不能访问整个 32 bits 的地址空间,所以需要在调用者和子程序之间插入一个 veneer,这段 veneer 是一段扩展程序,可以让 bl 指令实现 4gb 地址下的任意跳转,ip 寄存器将会被 veneer 程序使用,所以,当程序中可能将 r12 作为通用寄存器时,需要考虑 veneer 是否会存在从而导致程序出错。

事实上,在 armv7 中,并没有看到 veneer 的踪迹,因为 arm 的调用约定被定义在 aapcs 中,并不是属于 armv7 指令集独有,所以这个特殊寄存器可能是针对老版本的 arm 指令集。

veneer参考地址

在 armv7 中,除了上文中讨论的通用处理器之外,还有一个非常重要的状态寄存器 CPSR(SPSR)。

参考

armv7-A-R 参考手册

aapcs(arm函数调用标准)

----------------

欢迎关注公众号——“IC硅农场”

--------------------------------------------------------------------------------------------如侵权请联系删除-------------

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值