今天学习了ARM架构的第二天内容,主要围绕ARM汇编指令的基础概念、寻址方式、栈操作以及汇编与C语言的混合编程展开。图三的8个作业问题非常精准地概括了今天的核心考点。下面我将结合课件内容,对这8个问题进行详细的总结和梳理,形成这篇学习博客。
- 什么是立即数?立即数判断的规则?
定义:立即数是指在指令中直接给出的常数,而不是存储在寄存器或内存中的值。例如 MOV R0, #0x234 中的 0x234 就是立即数。
判断规则(合法性):ARM指令长度是32位,留给立即数的空间通常只有12位。这12位由 8位常数(immediate_8) 和 4位循环右移位数(rotate_4) 组成。
换算公式:立即数 = immediate_8 循环右移 (2 * rotate_4)。也就是说,这个8位的数可以通过循环右移偶数位(0, 2, 4, ..., 30)来得到。如果一个数无法通过这种方式生成,它就是非法立即数。
课件案例:0x234 可以,但 0x3f4 等如果无法由8位数据循环右移得到,就是无效的。像 0x0fa00,则需要通过旋转位来构成。
- Ldr 和 str 指令作用?
LDR (Load Register):加载指令。用于将内存中的数据加载到通用寄存器中,或者将立即数加载到寄存器中(伪指令形式,如 ldr r0, =0x12345678 常用于加载大常数)。
STR (Store Register):存储指令。用于将通用寄存器中的值写入到内存(RAM)中。
核心区别:LDR是读内存/取数据,STR是写内存/存数据。
- BIC 和 ORR 指令作用?
BIC (Bit Clear):位清零指令。将源寄存器中的位与目标寄存器进行操作,如果源寄存器某位为1,则目标寄存器对应位清零;如果为0,则保持不变。常用于清除某些特定的标志位。
ORR (Bitwise OR):位置1指令。将两个寄存器的值进行按位或运算,或者将立即数与寄存器进行按位或运算。常用于将特定位置1。
- STMFD 和 LDMFD 指令作用?
STMFD (Store Multiple Full Descending):入栈保护指令。将多个寄存器(通常配合 {r0-r1, lr} 等寄存器列表)的值压入栈中。FD 代表"满递减"(Full Descending)栈。
LDMFD (Load Multiple Full Descending):出栈恢复指令。将栈中保存的数据依次弹出,恢复到对应的寄存器中。常用于函数返回前恢复现场。
- B、BL、BX 指令区别?
B (Branch):无条件跳转指令。直接跳转到目标地址执行,不保存返回地址。常用于循环、条件分支(配合条件码)或函数内跳转。
BL (Branch with Link):带链接的跳转指令(函数调用)。在跳转之前,会自动将下一条指令的地址保存到 LR (R14) 寄存器中。这样函数执行完后可以通过 MOV PC, LR 返回到调用处。
BX (Branch and Exchange):带状态切换的跳转指令。跳转到寄存器(如 bx lr)中保存的地址,并且可以根据寄存器最低位切换ARM/Thumb指令状态。bx lr 等价于 mov pc, lr,但BX支持状态切换,更推荐使用。
- MRS 和 MSR 指令作用?
这两条指令用于通用寄存器与状态寄存器(CPSR/SPSR)之间的数据传递。
MRS (Move to Register from Status):读取状态寄存器。将CPSR或SPSR的值读入通用寄存(如 mrs r0, cpsr)。通常用于查看当前处理器的状态(如工作模式、中断使能位)。
MSR (Move to Status from Register):写入状态寄存器。将通用寄存器的值写入CPSR或SPSR(如 msr cpsr, r0)。常用于切换处理器模式(如切换到USER模式)、开启/关闭中断等。
注意:MRS和MSR不能直接操作立即数,必须通过通用寄存器中转。
- 栈有哪几种类型?ARM采用何种栈?
· 栈的分类(根据栈指针的移动方向和入栈顺序):
-
满增栈 (FA):栈指针先加,再存数据。
-
满减栈 (FD):栈指针先减,再存数据。
-
空增栈 (EA):先存数据,栈指针再加。
-
空减栈 (ED):先存数据,栈指针再减。
ARM采用何种栈?:ARM架构通常采用 满减栈 (FD, Full Descending)。即入栈时,SP(栈指针)先减小,再存入数据(课件提到:STMFA 和 LDMFD)。在ARM的异常处理中,默认使用的是满减栈。
- 汇编中调用C语言函数需要注意什么?
参数传递:
当参数小于等于4个时,通过通用寄存器 R0 - R3 进行传递。
当参数超过4个时,剩余的参数必须通过栈进行传递。此时需要通过 STMFD 入栈保护,使用完后通过 LDMFD 出栈恢复。
返回值:C语言函数的运行结果(返回值)默认放在 R0寄存器 中返回给汇编代码。
寄存器保护:汇编调用C函数前,如果有需要保留的寄存器(如R4-R11),通常需要手动压栈保护,因为C编译器可能会修改这些寄存器的值。
栈对齐:ARM架构通常要求栈是8字节对齐的,调用C函数时需注意SP的对齐情况。
学习心得
ARM汇编是底层开发的基石。今天的课程让我理解了CPU是如何通过简单的指令(加载、存储、跳转、位运算)来完成复杂的逻辑的。特别是栈的操作和C语言混合编程的接口规范(ATPCS),是后续理解操作系统内核、中断处理和函数调用栈帧的关键。接下来的学习中,我会多加练习汇编与C的相互调用,加深对这些指令的实际理解。