汇编之数据处理指令

文章目录

为什么要学汇编编程

复制代码
- 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
  • 练习:将r0寄存器的bit3清0
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
  • 练习:将r0寄存器的bit3置1
z80 复制代码
mov r0, #0x00
mov r1, #1
orr r0, r0, r1, lsl #3
  • 练习:将r0寄存器的bit3取反
z80 复制代码
mov r0, #0xff
mov r1, #1
eor r0, r0, r1, lsl #3
相关推荐
白太岁1 天前
操作系统开发:(11) RTOS 与 GPOS 的分界线:MMU
c语言·开发语言·汇编·arm开发·系统架构
枷锁—sha2 天前
【pwn系列】Pwndbg 汇编调试实操教程
网络·汇编·笔记·安全·网络安全
白太岁2 天前
C++:(4) 内存布局、编译流程、关键字及其链接性
c语言·汇编·jvm·c++
fly的fly3 天前
浅析 QT远程部署及debug方案
qt·物联网·arm
real_ben_ladeng5 天前
程序人生—Hello’s P2P 2dc736403375808d93f9c97fc816f2f8
c语言·汇编·硬件架构
切糕师学AI5 天前
ARM标准汇编(armasm)中的“定义”(Assembler Directive)
汇编·arm开发
切糕师学AI5 天前
ARM标准汇编(armasm)中的标号(Label)
汇编·arm
CHANG_THE_WORLD6 天前
字符串定义的汇编分析
汇编·数据库
CHANG_THE_WORLD6 天前
深入理解C语言指针:从源码到汇编的彻底剖析
c语言·开发语言·汇编