硬件6----arm指令

📅 2026/7/18 4:13:23 👁️ 阅读次数 📝 编程学习
硬件6----arm指令

ARM 汇编指令是 ARM 处理器的机器语言,直接控制硬件执行操作。理解 ARM 汇编对于底层开发、性能优化和调试非常重要。

学习arm汇编的主要目的是为了编写arm启动代码,启动代码启动以后,引导程序到c语言环境下运行。换句话说启动代码的目的是为了在处理器复位以后搭建c语言最基本的需求。因此启动代码的主要任务有:

  1. 初始化异常向量表;
  2. 初始化各工作模式的栈指针寄存器;
  3. 开启arm内核中断允许;
  4. 将工作模式设置为user模式;
  5. 完成上述工作后,引导程序进入c语言主函数执行;

mov

加载12位立即数到寄存器或转移一个寄存器的值到另外一个寄存器

mov r0, #2 ;加载立即数2到寄存器r0,MOV{S}<c> <Rd>, #<const>

mov r1, r0 ;将r0寄存器的值加载到r1,MOV{S}<c> <Rd>, <Rm>

大多数指令的格式为opcode rd, rn ,rm,其中,rd是目标寄存器,rn是第一操作数寄存器

; mov r0, #1 ; mov r1, #2 ; mov r2,r1 ; mov r3,r0,lsl #2 ; mov r4,r3,lsl r1

add

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

ADDS}<c> <Rd>, <Rn>, <Rm>{, <shift>}

ADD R0, R1, R2 ; R0 = R1 + R2 ADD R0, R1, #10 ; R0 = R1 + 10 ADD R0, R1, R2, LSL #2 ; R0 = R1 + (R2 <<

sub

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

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

SUB R0, R1, R2 ; R0 = R1 - R2 SUB R0, R1, #10 ; R0 = R1 - 10

立即数

立即数(Immediate)是 ARM 汇编中直接写在指令里的常数,不需要从内存或寄存器读取。

判断条件

立即数是直接写在指令中的常数。ARM 指令只有 12 位给立即数,所以不是所有数字都能直接加载。LDR 伪指令可以加载任意 32 位数,编译器会自动处理。记住:MOV 有立即数限制,LDR 没有限制。

LDR,SDR

ldr r0 ,=0x40000000 ldr r1 ,[r0] ldr r0, =0x40000004 ldr r2, [r0] add r3,r1,r2 ldr r0,=0x40000008 str r3,[r0]
STR R0, [R1] ; *R1 = R0(将 R0 的值存到 R1 指向的地址) STR R0, [R1, #4] ; *(R1+4) = R0 STR R0, [R1, R2] ; *(R1+R2) = R0

cmp比较指令

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

如:

mov r0, #100

cmp r0, #100

会导致Z置位,从条件码表可知,只要Z置位就是两数相等。

esp:

mov r0,#1 mov r1,#3 mov r3,#5 cmp r0,r1 movlt r2,r1 movgt r2,r0 cmp r2,r3 movlt r2,r3

用汇编来写dowhile循环

mov r0,#1 mov r1,#0 lable add r1,r0,r1 add r0,r0,#1 cmp r0,#100 ble table finished b finish

B、BL、BX

指令全称核心作用是否保存返回地址是否切换状态
BBranch无条件跳转❌ 不保存❌ 不切换
BLBranch with Link函数调用✅ 保存到 LR❌ 不切换
BXBranch and eXchange跳转并切换状态❌ 不保存✅ 可切换
场景用什么指令原因
函数调用(要回来)BL需要保存返回地址到 LR
无条件跳转(不用回来)B不需要返回地址,节省代码
无限循环B自己b .b label
函数返回BX LR根据 LR 最低位自动切换状态
状态切换BX Rm切换 ARM/Thumb 模式
调用 Thumb 函数BLX带返回的状态切换调用

栈区的保护

arm栈的四种类型

类型名称增长方向SP指向
FA满增栈向高地址最后一个数据
EA空增栈向高地址下一个空位
FD满减栈向低地址最后一个数据
ED空减栈向低地址下一个空位

STMFD= Store Multiple Full Descending 存储多个寄存器到满递减栈LDMFD= Load Multiple Full Descending 从满递减栈加载多个寄存器
_asm_max mov r0,#20 mov r1,#10 stmfd sp!,{r0,r1,lr}//入栈 bl _asm_min ldmfd sp!,{r0,r1,lr}//出栈 cmp r0,r1 movgt r2,r0 movlt r2,r1 mov pc,lr bx lr

关于c函数的调用

首先框架开头加上PRESERVE8

PRESERVE8是 ARM 汇编中的一个伪指令,用于告诉链接器代码的栈对齐要求,确保栈在函数调用边界是8 字节对齐

作用:

import

import(在 C 语言中用#include)是调用 C 函数的前提条件,它告诉编译器函数的声明(函数原型),让编译器知道如何正确调用这个函数。

ldr sp,=0x40001000 import c_add mov r0,#3 mov r1,#4 mov r2,#5 mov r3,#6 stmfd sp!,{r0-r12,lr} stmfd sp!,{r4} bl c_add ldmfd sp!,{r0-r12,lr} ldmfd sp!,{r4} stmfd sp!,{r0-r12,lr} bl _asm_max ldmfd sp!,{r0-r12,lr}

其中的参数传递

将c语言传递的参数保存到通用寄存器,返回值保存到r0

export

export在 ARM 汇编中用于将符号(函数名、变量名)导出,让其他文件(C 或汇编)可以调用。它是实现模块化编程跨文件调用的关键。

_asm_fn export _asm_fn svc #7 bx lr