ARM-汇编的基础知识

指令集版本:ARMv7-A

1.汇编指令

mov 指令:加载12位立即数到寄存器或转移一个寄存器的值到另一个寄存器

例如:

mov r0, #8 MOV{S}<C> <Rd>, #<const>

mov r1, r0 MOV{S}<C> <Rd>, <Rn>

Rd是目标寄器,Rn是第一操作寄存器

add指令:

add r0, r1, #12 ADD{S}<C> <Rd>, <Rn>, #<const>

add r0, r0, r1 ADD{S}<C> <Rd>, <Rn>, <Rm>

类似指令:sub指令(减法)

SUB{S}<c> <Rd>, <Rn>, #<const>

SUB{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}

判断一个数是不是立即数

1.如果某个数的数值范围是0~0xFF之间,那么这个数一定是立即数

2.把某个数展开成2进制,这个数的最高位1至最低位1之间的二进制数序列的位数不能超过8位

3.这个数的二进制序列凑够8位之后的的右边必须为偶数个连续的 0

例如:0x234 = 0000 0000 0000 0000 0000 0010 0011 0100

最高位1至最低位1之间的二进制数序列:1000 1101没有超过8位末尾1的右边有2个0,所以0x234是立即数

0x132 = 0000 0000 0000 0000 0000 0001 0011 0010

最高位1至最低位1之间的二进制数序列:1001 1001 从第一个1开始到最后一个1之间没有超过8位

末尾1的右边有1个0,不满足第二条,所以0x132不是立即数

判断一个数是否为有效的 ARM 立即数,需要看它能否通过8 位基值(Byte)和 4 位循环右移量(Shift) 组合生成。

1. ldr 寄存器加载指令(Load Register)

  • 功能:从内存读取数据到寄存器。
  • 格式ldr <目标寄存器>, <内存地址>
  • 说明:支持直接地址、寄存器间接寻址、带偏移量的寻址等。
cs 复制代码
ldr r0, =0x12345678  ; 将立即数0x12345678加载到r0(伪指令,实际可能转为mov或ldr)
ldr r1, [r2]         ; 读取r2指向的内存地址的数据到r1
ldr r3, [r4, #4]     ; 读取r4+4地址处的数据到r3(前索引寻址)
ldr r5, [r6], #8     ; 读取r6指向的地址数据到r5,之后r6 +=8(后索引寻址)

2. bic 指令(Bit Clear)

  • 功能:清除寄存器中的特定位(按位与非操作)。
  • 格式bic <目标寄存器>, <源寄存器1>, <源寄存器2/立即数>
  • 运算逻辑目标寄存器 = 源寄存器1 & (~源寄存器2/立即数)
cs 复制代码
bic r0, r1, #0x0F    ; 清除r1的低4位(0x0F对应二进制低4位为1),结果存到r0
bic r2, r3, r4       ; 清除r3中与r4对应为1的位,结果存到r2

3. orr 指令(Bitwise OR)

  • 功能:对寄存器进行按位或操作,可用于设置特定位。
  • 格式orr <目标寄存器>, <源寄存器1>, <源寄存器2/立即数>
  • 运算逻辑目标寄存器 = 源寄存器1 | 源寄存器2/立即数
cs 复制代码
orr r0, r1, #0x01    ; 置位r1的第0位(最低位),结果存到r0
orr r2, r3, r4       ; r3与r4按位或,结果存到r2

4. str 指令(Store Register)

  • 功能:将寄存器中的数据写入内存。
  • 格式str <源寄存器>, <内存地址>
  • 说明 :寻址方式与ldr对应,方向相反(寄存器→内存)。
cs 复制代码
str r0, [r1]         ; 将r0中的数据写入r1指向的内存地址
str r2, [r3, #4]     ; 将r2中的数据写入r3+4地址处(前索引)
str r4, [r5], #8     ; 将r4中的数据写入r5指向的地址,之后r5 +=8(后索引)

汇编指令的s后缀:s后缀是指指令在执行过程中更新CPSR寄存器的N、V、C、Z

N: 在结果时有符号的二进制补码情况下,结果为负数,则N= 1;非负数, N=0.

Z:如果结果为0,则Z=1;如果结果为非零,否则Z=0。

C: 是针对无符号数最高有效位向更高位进位时C=1;减法中运算结果的最高有效位从更高位借位时C=0。

V :该位针对有符号位操作,两个最高有效位均为0的数相加,得到的最高有效位为1 或者

两个最高有效位均为1的数相加,得到的结果最高有效位为0;除了这两种情况以外V位为0

几乎所有的arm指令都可以在指令之后可选地增加执行条件

cs 复制代码
	cmp r0, r1    ;比较
	movge r3, r0 ;如果大于,将r0的值赋给r3
	movls r3, r1 ;如果小于,将r1的值赋给r3

CMP比较指令用于比较两个寄存器的值或者比较一个寄存器和立即数的值,其原理是对待比较的两个数求差,看结果是否为0,这个指令会无条件修改N,V,C,Z位

5.跳转指令

无条件跳转指令 b(Branch)

  • 功能:直接跳转到目标地址执行,不返回原地址。
cs 复制代码
start:
    mov r0, #1
    b loop       ; 无条件跳转到loop标签处
loop:
    add r0, r0, #1
    b loop       ; 循环跳转(死循环)

带链接的跳转指令 bl(Branch with Link)

  • 功能 :跳转前将下一条指令地址存入 lr(r14,链接寄存器),用于函数调用后返回。
cs 复制代码
main:
    bl add_func  ; 调用add_func,lr = 下一条指令地址(mov r1, r0)
    mov r1, r0   ; 函数返回后执行此句
    ...

add_func:
    add r0, r1, r2  ; 函数逻辑
    mov pc, lr      ; 从lr恢复返回地址,跳转回main

远跳转指令 ldr pc, =<目标地址>

通过加载 32 位地址到程序计数器(pc)实现大范围跳转(不受 ±32MB 限制

入方式栈有:满增、满减、空增、空减

arm体系采用的方案是满减

入栈保护指令:stmfd

STMFD<c> <Rn>{!}, <registers>

出栈恢复指令:ldmfd

LDMFD<c> <Rn>{!}, <registers>

向c函数传参

向c函数传参的方法很简单,如果参数个数小于等于4个,就直接用r0~r3传参,c函数返回值通过r0寄存器返回:

cs 复制代码
; 设置栈指针(SP)的值为0x40001000
; 栈是程序运行时用于临时存储数据和保存上下文的内存区域
ldr sp, =0x40001000  

; 将寄存器r0到r12以及lr(链接寄存器)的值压入栈中保存
; stmfd: 满递减栈(Stack Memory Full Descending),!表示更新sp的值
; 这一步是为了保护现场,防止后续操作修改这些寄存器的值
stmfd sp!, {r0-r12, lr}

; 导入外部的C语言函数c_max(声明该函数在其他文件中定义)
import c_max

; 给寄存器r0赋值5,r0将作为c_max函数的第一个参数
mov r0, #5
; 给寄存器r1赋值7,r1将作为c_max函数的第二个参数
mov r1, #7

; 将r0和r1的值压入栈中保存(临时保护这两个参数寄存器)
; 因为调用函数时可能会修改r0-r3,这里保存是为了后续可以恢复
stmfd sp!, {r0-r1}

; 调用C语言函数c_max,会自动将返回地址存入lr寄存器
; 函数执行完后会返回到下一条指令(ldmfd)
bl c_max

; 从栈中恢复r0和r1的值(出栈),!表示更新sp的值
; 恢复之前保存的参数寄存器
ldmfd sp!, {r0-r1}

; 从栈中恢复r0到r12以及lr寄存器的值(出栈)
; 恢复现场,还原调用前的寄存器状态
ldmfd sp!, {r0-r12, lr}

如果参数个数大于4个,从第五个参数开始就需要通过栈来传参

在c语言中调用汇编编写的函数类似,不过在汇编中用export 声明函数,同时需要在c语言中用extern声明函数,按照标准,调用者负责保护现场和恢复现场

MRS 和 MSR的用法

在 ARM 汇编中,mrsmsr 是用于访问特殊寄存器(如程序状态寄存器 CPSR/SPSR 等)的指令

mrs <通用寄存器>, <特殊寄存器>
cs 复制代码
mrs r0, cpsr  ; 将当前程序状态寄存器(CPSR)的值读取到r0
mrs r1, spsr  ; 将保存的程序状态寄存器(SPSR)的值读取到r1

读取 CPSR 中的标志位(如 Z、N、C、V 等)进行判断

msr <特殊寄存器><字段>, <通用寄存器/立即数>
cs 复制代码
msr cpsr_c, r0    ; 将r0的值写入CPSR的控制位字段(修改处理器模式、中断使能等)
msr cpsr, #0xD3   ; 直接写入立即数到CPSR(0xD3对应特权模式,关闭IRQ和FIQ中断)

** 字段说明:cpsr 可分为 4 个 8 位字段(c:控制位,x:扩展位,s:状态位,f:标志位),可指定修改特定字段(如 cpsr_c 仅修改控制位)

相关推荐
亿道电子Emdoor8 小时前
【Arm】解决Keil MDK报错提示找不到编译器路径的问题
arm开发
询问QQ6882388618 小时前
探索多虚拟电厂联合调度优化模型:集中式算法的实践
汇编
cooldream200918 小时前
RISC-V 全景解析:在 x86 与 ARM 之间,理解开放指令集的真正价值
arm开发·risc-v
草莓熊Lotso21 小时前
C++11 核心特性实战:列表初始化 + 右值引用与移动语义(附完整代码)
java·服务器·开发语言·汇编·c++·人工智能·经验分享
西西弗Sisyphus1 天前
读第三方程序的变量的原理
汇编
西西弗Sisyphus2 天前
一个程序点击事件的汇编指令与解析 - 目标变量的真实虚拟地址 = 逐级解引用并叠加偏移后的结果
汇编
切糕师学AI2 天前
ARM 架构中的数据内存屏障指令 DMB
arm开发·架构·指令·内存屏障
2501_918126913 天前
nes游戏语言是6502,有没有一种方法可以实现,开发另一种更高效的汇编语言,替代6052,并本土化,弯道超过nes的底层语言?
汇编·硬件工程·个人开发
啊森要自信3 天前
【C语言】 C语言文件操作
c语言·开发语言·汇编·stm32·单片机
云qq3 天前
x86操作系统19——键盘驱动
linux·c语言·汇编