ARM汇编基础(一)
1. 立即数的概念
在ARM汇编中,立即数(Immediate)是指直接编码在指令中的常数,而不是存储在寄存器或内存中的值。例如,MOV R0, #0xFF 中的 0xFF 就是一个立即数。
- 如果某个数的数值范围是0~0xFF之间,那么这个数一定是立即数;
- 把某个数展开成2进制,这个数的最高位1至最低位1之间的二进制数序列的位数不能超过8位;
- 这个数的二进制序列凑够8位之后的的右边必须为偶数个连续的 0

例如:0x234 = 0000 0000 0000 0000 0000 0010 0011 0100
最高位1至最低位1之间的二进制数序列:1000 1101没有超过8位
末尾1的右边有2个0,所以0x234是立即数
0x3f4 = 0000 0000 0000 0000 0000 0011 1111 0100
最高位1至最低位1之间的二进制数序列:1111 1101 从第一个1开始到最后一个1之间没有超过8位
末尾1的右边有2个0,所以0x3f4是立即数
0x132 = 0000 0000 0000 0000 0000 0001 0011 0010
最高位1至最低位1之间的二进制数序列:1001 1001 从第一个1开始到最后一个1之间没有超过8位
末尾1的右边有1个0,不满足第二条,所以0x132不是立即数
2. b、bl、bx指令的区别
这三条指令都用于实现程序跳转,但行为有所不同:
| 指令 | 功能 | 是否保存返回地址 |
|---|---|---|
b (Branch) |
无条件跳转到指定地址 | 否,不保存返回地址到LR寄存器 |
bl (Branch with Link) |
跳转到指定地址,并将返回地址保存到LR寄存器 | 是,自动将下一条指令地址存入LR |
bx (Branch and Exchange) |
跳转到寄存器中指定的地址,并可切换指令集(ARM/Thumb) | 否,但可通过寄存器间接跳转 |
使用场景:
b:用于简单的循环、条件分支,不需要返回。bl:用于函数调用,因为调用结束后可以通过MOV PC, LR返回。bx:用于函数返回或切换到Thumb模式,例如BX LR从函数返回。
3. 栈的四种类型
ARM架构中,栈(Stack)根据指针移动方向和压栈/出栈方式,可以分为四种类型:
| 栈类型 | 描述 |
|---|---|
| 满增栈 (Full Ascending, FA) | SP指向最后压入的数据,压栈时SP先增加,再存入数据 |
| 满减栈 (Full Descending, FD) | SP指向最后压入的数据,压栈时SP先减少,再存入数据 |
| 空增栈 (Empty Ascending, EA) | SP指向下一个空闲位置,压栈时先存入数据,SP再增加 |
| 空减栈 (Empty Descending, ED) | SP指向下一个空闲位置,压栈时先存入数据,SP再减少 |
4. 空栈、满栈、增栈、减栈的定义
- 满栈 (Full Stack):栈指针(SP)指向最后一个压入的数据。压栈时,先移动指针,再写入数据(
*--SP = data)。 - 空栈 (Empty Stack):栈指针(SP)指向下一个空闲位置。压栈时,先写入数据,再移动指针(
*SP++ = data或*SP-- = data)。 - 增栈 (Ascending Stack):压栈时,栈指针向高地址方向移动(SP增加)。
- 减栈 (Descending Stack):压栈时,栈指针向低地址方向移动(SP减少)。
5. ARM采用的栈类型
ARM处理器默认采用满减栈 (Full Descending, FD)。
这意味着:
- 栈指针(SP)指向栈中最后一个有效数据。
- 压栈时,SP先自减(向低地址移动),然后将数据存入新的SP位置。
- 出栈时,先从SP位置取出数据,然后SP自增。
ARM的 LDMFD 和 STMFD 指令就是专门为满减栈设计的批量数据加载/存储指令。
6. ldr和str指令的作用
LDR 和 STR 是ARM汇编中最基本的内存访问指令,用于在寄存器和内存之间传输数据。
-
LDR(Load Register):从内存地址加载数据到通用寄存器。- 格式:
LDR Rd, [Rn, #offset] - 示例:
LDR R0, [R1, #0x10]将地址R1+0x10处的4字节数据加载到R0。 - 作用:读取RAM、外设寄存器、Nor Flash等存储空间中的数据。
- 格式:
-
STR(Store Register):将通用寄存器的值写入到内存地址。- 格式:
STR Rd, [Rn, #offset] - 示例:
STR R0, [R1]将R0的值写入到R1指向的地址。 - 作用:将计算结果写回RAM或外设寄存器。
- 格式:
C语言对应关系:
int i = 2; // 对应 STR R0, [R1] (假设R0=2, R1=&i)
int j = 3; // 对应 STR R0, [R1] (假设R0=3, R1=&j)
int sum = 0; // 对应 STR R0, [R1] (假设R0=0, R1=&sum)
sum = i + j; // 对应 LDR R0, [R1]; LDR R2, [R3]; ADD R0, R0, R2; STR R0, [R4]
7. ldmfd和stmfd指令的作用
LDMFD 和 STMFD 是用于批量加载/存储多个寄存器的指令,专门配合ARM的满减栈(FD)使用。
-
STMFD SP!, {register list}:将寄存器列表中的值压入栈中(入栈)。- 示例:
STMFD SP!, {R0-R3, LR}将R0-R3和LR寄存器的值保存到栈中。 - 作用:在函数调用开始时,保存现场(被调用者需要使用的寄存器和返回地址)。
- 示例:
-
LDMFD SP!, {register list}:从栈中弹出数据到寄存器列表(出栈)。- 示例:
LDMFD SP!, {R0-R3, PC}从栈中恢复R0-R3的值,并将返回地址加载到PC(程序计数器)。 - 作用:在函数返回时,恢复现场并跳转回调用者。
- 示例:
典型函数调用模板:
my_function:
STMFD SP!, {R0-R3, LR} ; 保存现场
; ... 函数体 ...
LDMFD SP!, {R0-R3, PC} ; 恢复现场并返回
8. bic和orr指令的作用
BIC 和 ORR 是ARM汇编中的位操作指令,用于对寄存器中的特定位进行清零或置1。
-
BIC(Bit Clear):将操作数中为1的位清零,结果写回目标寄存器。- 格式:
BIC Rd, Rn, Operand2 - 示例:
BIC R0, R0, #0xF0将R0的第4-7位清零。 - 作用:用于屏蔽或清除特定位。
- 格式:
-
ORR(OR):将操作数中为1的位进行逻辑或运算,结果写回目标寄存器。- 格式:
ORR Rd, Rn, Operand2 - 示例:
ORR R0, R0, #0x0F将R0的低4位置1。 - 作用:用于设置或合并特定位。
- 格式:
应用场景:修改外设寄存器的特定位,而不影响其他位。例如,设置GPIO引脚为输出模式:
LDR R0, =GPIO_BASE
LDR R1, [R0, #GPIO_DIR] ; 读取当前方向寄存器
ORR R1, R1, #(1 << 10) ; 将第10位置1(设置为输出)
STR R1, [R0, #GPIO_DIR] ; 写回
9. mrs和msr指令的作用
MRS 和 MSR 是ARM汇编中用于访问特殊寄存器(主要是CPSR和SPSR)的指令。
-
MRS(Move to Register from Special register):将特殊寄存器的值读取到通用寄存器。- 格式:
MRS Rd, CPSR或MRS Rd, SPSR - 示例:
MRS R0, CPSR将当前程序状态寄存器(CPSR)的值读入R0。 - 作用:读取处理器状态标志、中断屏蔽位、处理器模式等。
- 格式:
-
MSR(Move to Special register from Register):将通用寄存器的值写入到特殊寄存器。- 格式:
MSR CPSR, Rm或MSR SPSR, Rm - 示例:
MSR CPSR, R0将R0的值写入CPSR。 - 作用:修改处理器模式、开关中断等。
- 格式:
典型应用:修改处理器工作模式为USER模式
MRS R0, CPSR ; 1. 读取CPSR到通用寄存器
BIC R0, R0, #0x1F ; 2. 将低5位(模式位)清零
ORR R0, R0, #0x10 ; 3. 设置为USER模式(10000)
MSR CPSR, R0 ; 4. 写回CPSR
10. 汇编向C传参的注意事项
当汇编代码调用C函数时,参数传递遵循ARM过程调用标准(AAPCS):
-
参数个数 ≤ 4个:通过通用寄存器
R0 - R3传递,依次对应第1到第4个参数。MOV R0, #3 ; 第一个参数 a = 3 MOV R1, #5 ; 第二个参数 b = 5 MOV R2, #7 ; 第三个参数 c = 7 BL max_of_three ; 调用C函数 int max_of_three(int a, int b, int c) ; 返回值保存在R0中 -
参数个数 > 4个:前4个参数仍通过R0-R3传递,第5个及之后的参数必须通过栈传递。调用者需要先将多余参数压栈,再调用函数。
; 假设调用 func(a, b, c, d, e, f) MOV R0, #a ; 第1个参数 MOV R1, #b ; 第2个参数 MOV R2, #c ; 第3个参数 MOV R3, #d ; 第4个参数 MOV R4, #e ; 第5个参数 MOV R5, #f ; 第6个参数 STMFD SP!, {R4, R5} ; 将第5、6个参数压栈 BL func ADD SP, SP, #8 ; 调用结束后,恢复栈指针 -
返回值:C函数的返回值通过
R0寄存器返回给汇编调用者。 -
寄存器保存规则:
- 被调用者保存:
R4-R11和LR,如果被调用函数使用了这些寄存器,必须在使用前保存,返回前恢复。 - 调用者保存:
R0-R3和R12,调用者如果需要在函数调用后继续使用这些寄存器的值,应自行保存。
- 被调用者保存:
-
栈对齐:ARM要求函数调用时栈指针(SP)必须8字节对齐,这是AAPCS规范的要求。
鲲鹏昇腾开发者社区是面向全社会开放的“联接全球计算开发者,聚合华为+生态”的社区,内容涵盖鲲鹏、昇腾资源,帮助开发者快速获取所需的知识、经验、软件、工具、算力,支撑开发者易学、好用、成功,成为核心开发者。
更多推荐


所有评论(0)