文章目录
为什么要学汇编编程
复制代码
- C语言是操作不到ARM核的
- <font style="color:rgb(51,51,51);">C语言是无法精准实现一条指令实现跳转的</font>
- <font style="color:rgb(51,51,51);">从实际工作情况看,汇编有着以下使用场景</font>
* <font style="color:rgb(51,51,51);">嵌入式系统需要初始化和中断服务程序中所有的系统都需要调试,可能汇编指令级调试,深层次的BUG需要汇编级的调试</font>
* <font style="color:rgb(51,51,51);">可以通过汇编语言编程来提升系统性能(优化)</font>
* <font style="color:rgb(51,51,51);">有些指令编译器无法产生,只能通过汇编完成</font>
z80
复制代码
.text
.global _start @将_start声明为全局的
_start:
mov r0, #100 @r0=100
mov r1, #200 @r1=200
add r2, r0, r1 @r2=r0+r1
nop
b .
.end
- 汇编程序中一般由三部分内容组成: 指令、伪指令、伪操作
- ARM汇编程序中单行注释使用@符号, 多行注释 /* */
ARM汇编的本质和特点
- 汇编程序的本质:助记符语言
- 助记符语言,类似于人类语言,人容易看懂,相对来说编写、维护方便。
- 机器语言,CPU能看懂并执行,但人类不容易看懂
- 汇编工具,用于将汇编语言(人类容易看懂的), 翻译为机器能看懂的机器语言
- ARM汇编的特点
- 大多数指令都是单周期指令。像加法运行、减法运算、位运算都是单周期指令。而乘法指令则是多周期指令
- 大多数指令都是可以条件执行的
c
复制代码
if (r0 == 0)
{
r1 = r1 + 1;
} else {
r2 = r2 + 1;
}
z80
复制代码
@无条件执行 5条指令解决问题
CMP r0, #0
BNE else
ADD r1, r1, #1
B end
else:
ADD r2, r2, #1
end:
z80
复制代码
@条件执行 3条汇编指令解决问题
CMP r0, #0
ADDEQ r1, r1, #1
ADDNE r2, r2, #1
ARM汇编指令
数据处理指令
数据传输指令
z80
复制代码
mov{cond}{s} <Rd>, <shifter_operand>
实例,
mov r0, #1 @r0=1
cond, 条件码
moveq r0, #1 @if(Z==1) mov r10, #1
s, 操作结果影响NZCV的取值
movs r0, #0 @ s, 操作结果影响CPSR NZ
@ r0 = 0
@ cpsr.N = r0[31]
@ if r0==0 CPSR.Z=1 else CPSR.Z=0
Rd, 通用寄存器
shifter_operand, 第二个操作数 有三种表现形式
立即数, mov r3, #1
寄存器, mov r3, r4
寄存器移位之后的值, mov r3, r4, lsl #2 @r3 = r4 * 4
注意,使用立即数时要关注立即数的合法性问题
如果给定的立即数可以通过一个8bit的数据循环右移偶数位得到,那么该累计数就合法
| 组成部分 |
含义与用法 |
可选 / 必选 |
核心规则 |
mov |
指令助记符,固定表示 "数据传送" |
必选 |
无 |
{cond} |
条件码后缀,指定指令执行的条件 |
可选 |
1. 共 16 种(如 eq/ne/gt/lt/al 等),默认 al(无条件执行)2. 仅当 CPSR 中条件标志位满足时,指令才执行 |
{s} |
状态位影响后缀,指定是否修改 CPSR 的条件标志位(N/Z/C/V) |
可选 |
1. 加 s:执行后更新 CPSR(仅对 Rd=R15或移位操作数影响标志位时生效)2. 不加 s:不修改 CPSR(默认) |
<Rd> |
目标寄存器,接收数据的寄存器(如 R0~R15) |
必选 |
1. R15 是 PC(程序计数器),向 PC 传值等价跳转2. 不能同时指定 {s}且 Rd=R15ARMv4 及以上) |
<shifter_operand> |
移位操作数(ARM 特有的灵活操作数),有 2 种形式 |
必选 |
见"移位操作数详细规则" |
z80
复制代码
mvn{cond}{s} <Rd>, <shifter_operand> @第二个操作数取反后赋值
实例: mvn r0, #0xff @r0=0xffffff00
- 只要该立即数可以通过一个8bit的立即数循环右移偶数位得到,那这个立即数就是合法的
移位操作指令
z80
复制代码
lsl{cond}{S} <Rd>, <Rm>, 立即数/寄存器 #逻辑左移 logical shift left
lsr{cond}{S} <Rd>, <Rm>, 立即数/寄存器 #逻辑右移 logical shift right
asr{cond}{S} <Rd>, <Rm>, 立即数/寄存器 #算术右移 arithmetic shift right
ror{cond}{S} <Rd>, <Rm>, 立即数/寄存器 #循环右移 Rotate right
rrx{cond}{S} <Rd>, <Rm> #带扩展位的循环右移
z80
复制代码
mov r0, #1
lsl r1, r0, #1
lsl r2, r0, r1
mov r5, #0x8f000000
lsr r6, r5, #1
asr r7, r5, #1
ror r8, r5, #1
lsr r6, r0
asr r7, r0
ror r8, r0
mov r9, #0xff
ror r9, #1
rrx r9, r0
mov r0, r1, lsl #3 @ r0 = r1 * 8
mov r0, r2, lsr #1 @ r0 = r2 >>1
算数运算指令
z80
复制代码
add{cond}{s} <Rd>, <Rn>, <shifter_operand>
Rd,通用寄存器
Rn,通用寄存器
shifter_operand, 三种形式: 立即数 寄存器 寄存器移位之后的值
s, 操作结果影响 NZCV
N = Rd[31]
Z if Rd ==0 then Z=1 else Z=0
C 最高位有进位 C=1 反之 C=0
V 有符号算术操作是否发生了溢出。溢出V=1, 反之V=0
两个最高位为0的数据(正整数)运算结果最高位为1,则溢出 V=1
两个最高位为1的数据(负整数)运算结果最高位为0,则溢出 V=1
adc{cond}{s} <Rd>, <Rn>, <shifter_operand>
adc r0, r1, r2 @r0 = r1 + r2 + C
sub/sbc/rsb/rsc{cond}{s} <Rd>, <Rn>, <shifter_operand>
C, 够减无借位 C= 1 反之 C=0
sbc r0, r1, r2 @r0=r1-r2-NOT(C)
rsb r0, r1, r2 @r0=r2 - r1
rsc r0, r1, r2 @r0=r2 - r1 - NOT(C)
mul{cond}{s} <Rd>, <Rn>, <Rs> @32位乘法指令
@div 除法指令, arm-v7架构不支持除法指令,arm-v8之后的架构支持除法指令
z80
复制代码
add r0, r1, r2 @ r0 = r1 + r2
add r0, r1, #3 @ r0 = r1 + 3
add r0, r1, r2, lsl #3 @ r0 = r1 + r2 *8
adds r0, r1, #0xff000000
addeq r0, r1, r2 @if Z==1 add r0, r1, r2
sub r0, r1, r2 @ r0=r1-r2
sub r0, r1, #8 @ r0 = r1 -8
sub r0, r1, r2, lsl #1 @ r0=r1-r2*2
sbc r0, r1, r2 @ r0 = r1 -r2 - NOT (C)
rsb r0, r1, r2 @ r0 = r2 - r1
rsc r0, r1, r2 @ r0 = r2 - r1 - NOT (C)
mul r0, r1, r2 @ r0 = r1 * r2
- 练习:64位加法运算
- 被加数高32bit存储在r1, 低32bit存储在r0
- 加数高32bit存储在r3, 低32bit存储在r2
- 和高位存储到r5, 低位存储到r4
z80
复制代码
ADDS R4, R0, R2 @ R0+R2 最高位有进位 会体现位C=1 无进位C=0
ADC R5, R1, R3
- 练习:64位减法运算
- 被减数高32bit存储在r1, 低32bit存储在r0
- 减数高32bit存储在r3, 低32bit存储在r2
- 差高位存储到r5, 低位存储到r4
z80
复制代码
SUBS R4, R0, R2 @如果r0>r2够减C=1 反之 C=0
SBC R5, R1, R3 @R5=R1-R3-NOT(C)
位运算指令
z80
复制代码
and{cond}{s} <Rd>, <Rn>, <shifter_operand> @ 按位与 &
orr{cond}{s} <Rd>, <Rn>, <shifter_operand> @ 按位或 |
eor{cond}{s} <Rd>, <Rn>, <shifter_operand> @ 按位异或 ^
bic{cond}{s} <Rd>, <Rn>, <shifter_operand> @ 按位清0
s, 操作结果影响 NZC
N = Rd[31]
if Rd ==0 then Z=1 else Z=0
cond, 可以条件执行
z80
复制代码
and r0, r1, #0xff @ r0 = r1 & 0xff
and r0, r1, r2 @ r0 = r1 & r2
and r0, r1, r2, lsl #3 @r0 = r1 & (r2*8)
orr r0, r1, r2 @r0 = r1 | r2
eor r0, r1, #0x80 @ r0 = r1 ^ 0x80
bic r0, r0, #0x08 @ 将r0的bit3清0
比较测试指令
z80
复制代码
cmp{cond} <Rn>, <shifter_operand> @比较大小 按照减法运算结果影响NZCV
tst{cond} <Rn>, <shifter_operand> @位测试指令 按照与运算结果影响NZ
teq{cond} <Rn>, <shifter_operand> @测试是否相等 按照异或运算影响NZ
- 不用+s 默认就影响NZCV的取值,操作结果不保存
z80
复制代码
cmp r0, r1
addeq r2, r2, #1
subeq r3, r5, #6
tst r0, #0x01 @测试r0的bit0是否为0
addeq r2, r2, #1
teq r2, r3
addeq r5, r6, r7
z80
复制代码
mov r1, #1
mov r2, r1, lsl #3
mvn r3, r2
and r0, r0, r3
@或
mov r0, #0xff
mov r1, #1
mov r2, r1, lsl #3
bic r0, r0, r2
z80
复制代码
mov r0, #0x00
mov r1, #1
orr r0, r0, r1, lsl #3
z80
复制代码
mov r0, #0xff
mov r1, #1
eor r0, r0, r1, lsl #3