文章目录
-
- 前言
- 一、程序状态寄存器
- 二、立即数(imm)的概念
- 三、汇编指令
-
- mov指令
- add指令
- sub指令
- ldr指令
- str指令
- bic指令
- orr指令
- CMP指令
- b指令
- 四、s后缀
- 五、ARM CPSR 常用条件码
- 六、栈的分类
- 七、汇编和C语言混合编程
-
- 7.1 汇编调用C函数
- 7.2 C调用汇编函数
- 八、切换处理器工作模式为USER模式

前言
由于使用arm芯片时,其本身是不能直接使用C语言环境进行程序设计的,所以我们需要简单学习汇编指令来编写arm芯片的启动程序,使其能够使用C环境,即启动代码启动以后,引导程序到C语言环境下运行。换句话说启动代码的目的是为了在处理器复位以后搭建 c 语言最基本的需求。
一、程序状态寄存器

二、立即数(imm)的概念
8位、10位、12位
立即数的判断:
例:
-
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不是立即数
-
0x7f8 = 0000 0000 0000 0000 0000 0111 1111 1000 最高位1至最低位1之间的二进制数序列:1111 1111从第一个1开始到最后一个1之间没有超过8位 末尾1的右边有3个0,不满足第二条,所以0x7f8不是立即数
-
0xfab4 = 0000 0000 0000 0000 1111 1010 1011 0100 最高位1至最低位1之间的二进制数序列:0011 1110 1010 1101 从第一个1开始到最后一个1之间超过8位,不满足条件1,所以这个数不是立即数
ARM 指令机器码只有12bit 用来存立即数,放不下完整 32 位数字,拆成两部分:
最终 32 位立即数 = imm8 循环右移 2×rotate 位(移位步数永远是偶数:0、2、4 … 30 位。) 如上图:ADD R0, R1, #0xFA00 ; 合法,汇编器算出rotate=12 imm8=0xFA,填入机器码12bit
三、汇编指令
mov指令
加载12位立即数到寄存器或转移一个寄存器的值到另外一个寄存器; MOV{S}<c> <Rd>, #<const>
例: mov r0, #2 ;加载立即数2到寄存器r0
MOV{S}<c> <Rd>, <Rm>
例: mov r1, r0 ;将r0寄存器的值加载到r1
add指令
ADD{S}<c> <Rd>, <Rn>, #<const>
例: ADD R0, R1, #1 ; R0 = R1 + 1,不更新标志 ADDS R0, R1, #0xFF ; R0 = R1 + 0xFF,更新N/Z/C/V
ADD{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
例: ADD R0, R1, R2 ; R0 = R1 + R2 ADD R0, R1, R2, LSL #2 ; R0 = R1 + (R2 << 2)
sub指令
SUB{S}<c> <Rd>, <Rn>, #<const>
例: SUB R0, R1, #5 ; R0 = R1 − 5,不更新标志 SUBS R0, R1, #0x10 ; R0 = R1 − 0x10,更新N/Z/C/V
SUB{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
例: SUB R0, R1, R2 ; R0 = R1 − R2 SUB R0, R1, R2, LSL #1 ; R0 = R1 − (R2 << 1)
ldr指令
功能1:将非立即数加载到通用寄存器 LDR{<c>}{<q>} <Rt>, <label>
例:如ldr r0, =0x2FAB4
功能2:将RAM中的数据加载到通用寄存器 LDR<c> <Rt>, [<Rn>{, #+/-<imm12>}]
例:ldr r0,[r1,#4];将内存地址为R1+4的字数据读入寄存器R0
LDR<c> <Rt>, [<Rn>], #+/-<imm12>
例:ldr r0, [r1], #8 ;将内存地址R1的字数据读入r0,之后r1+8
LDR<c> <Rt>, [<Rn>, #+/-<imm12>]!
例:LDR R0,[R1,#8] ! ;将存储器地址为R1+8的字数据读入寄存器R0,并将新地址R1+8写入R1。
str指令
将通用寄存器中的值写入到RAM中
str r1, [r0] ;*r0 = r1
str r1, [r0, #4] ;*(r0 + 1) = r1
str r1, [r0], #4 ;*r0++ = r1
str r1, [r0, #4]! ;*++r0 = r1
bic指令
将某个通用寄存器清零(操作数中为bit1的位清0),清0结果写回到通用寄存器。 BIC{S}<c> <Rd>, <Rn>, #<const>; 将rn中的字数据const为1的比特清零,把结果放入rd。
例: mov r0, #0xff bic r0, #1 此时r0中的值为0xfe
orr指令
将某个通用寄存器置1(操作数中为bit1的位置1),置1结果写回到通用寄存器
例: mov r0, #0 orr r0, #(1 << 6) ;0100 0000 此时r0中的值为0100 0000。
CMP指令
比较两个寄存器的值或者比较一个寄存器和立即数的值,其原理是对待比较的两个数求差,看结果是否为0,这个指令会无条件修改N,V,C,Z位。
例: mov r0, #100 cmp r0, #100 会导致Z置位,从条件码表可知,只要Z置位就是两数相等。
b指令
实现无条件跳转; b指令条件分支 b指令循环 b函数调用 bl指令:函数跳转前,会将函数返回地址保存到lr寄存器; bx指令:bx lr 等价于mov pc, lr,bx指令加一个地址。
使用示例:

四、s后缀
汇编指令的 s 后缀,几乎所有的汇编指令都可以在指令后面加上 s 后缀,s 后缀的含义是在指令执行过程中会更新 cpsr 寄存器的 N,V,C,Z 位。
例:
- ADDS R3,R0,R1 ; R3 = 0,带S,更新标志:Z=1,C=1
- SUBS R3,R0,R1 ; R3 = 0xFFFFFFFB,带S更新标志; 结果负数 N=1;发生借位 C=0;无符号溢出V=0;Z=0
- …
五、ARM CPSR 常用条件码
| EQ | Equal | Z=1 | 等于 | 通用 |
| NE | Not Equal | Z=0 | 不等于 | 通用 |
| CS/HS | Carry Set / Higher or Same | C=1 | 进位置1 / 无符号≥ | 无符号比较 |
| CC/LO | Carry Clear / Lower | C=0 | 进位清零 / 无符号< | 无符号比较 |
| MI | Minus | N=1 | 结果为负数 | 符号判断 |
| PL | Plus | N=0 | 结果非负(≥0) | 符号判断 |
| VS | Overflow Set | V=1 | 有符号溢出 | 溢出判断 |
| VC | Overflow Clear | V=0 | 无有符号溢出 | 溢出判断 |
| GT | Greater Than | N==V && Z==0 | 有符号> | 有符号比较 |
| GE | Greater or Equal | N==V | 有符号≥ | 有符号比较 |
| LT | Less Than | N!=V | 有符号< | 有符号比较 |
| LE | Less or Equal | `N!=V | Z==1` |
例:
-
CMP R0, R1 ; R0‑R1,更新标志,Z=1 ADDEQ R2, R2, #1 ; ✅条件成立,R2 = R2 +1
-
cmp r0, r1 blt lable1 bgt lable2 执行 R0‑R1 的运算并更新 CPSR 状态标志,不保存运算结果;blt lable1为有符号小于条件跳转,若满足有符号 R0<R1(N≠V),就跳转到 lable1;bgt lable2为有符号大于条件跳转,若满足有符号 R0>R1(N==V 且 Z=0),就跳转到 lable2;
六、栈的分类
满栈/空栈(是一种结构,不是传统字面意思的满空):根据栈顶所在位置是否存有元素确定。 栈顶所在位置一直存有元素称为满栈,先移动栈顶再存入数据; 栈顶所在位置一直没有元素称为空栈,先存入数据再移动栈顶。
增栈/减栈:根据栈的生长方向确定。 入栈数据时,栈顶向内存高地址移动,称为增栈; 入栈数据时,栈顶向内存低地址移动,称为减栈,
注意:ARM中的栈结构为:满减栈。
七、汇编和C语言混合编程
汇编调用C函数C调用汇编函数
7.1 汇编调用C函数
汇编和C语言混合编程(汇编调用C函数C调用汇编函数) 汇编如何向c语言传参: C语言将函数运行结果返回给R0寄存器 当参数小于等于4个时,通过通用寄存器进行传参(R0-R3) 
当参数超过4个时,必须通过栈进行传参(入栈保护出栈恢复) 
7.2 C调用汇编函数
C语言向汇编函数传参,参数会被保存到通用寄存器汇编函数的结果通过R0寄存器返回给C语言 
八、切换处理器工作模式为USER模式
1.将cpsr寄存器中的值读到R0寄存器 2.将R0寄存器中的值修改为10000 3.将R0寄存器中的值写回到cpsr寄存器 mrs指令:读取某个特殊寄存器(cpsr)的值到通用寄存器 msr指令:将通用寄存器中的值写入到特殊寄存器(cpsr)
例: MRS , <spec_reg> mrs r0, cpsr MSR<spec_reg>, msr cpsr, r0
网硕互联帮助中心





评论前必须登录!
注册