ARMv7 架构的汇编指令集大全

@ *****************************************************************

@ 汇编中的符号

@ 1.指令: 能够编译生成一条32位的机器码,且能被CPU识别和执行

@ 2.伪指令:本身不是指令,编译器可以将其替换成若干条等效指令

@ 3.伪操作:不会生成代码,只是在编译之前告诉编译器怎么编译

@ ARM指令

@ 1.数据处理指令: 数学运算、逻辑运算

@ 2.跳转指令: 实现程序的跳转,本质就是修改了PC寄存器

@ 3.Load/Srore指令: 访问(读写)内存

@ 4.状态寄存器传送指令:访问(读写)CPSR寄存器

@ 5.软中断指令: 触发软中断异常

@ 6.协处理器指令: 操控协处理器的指令

@ *****************************************************************

.text @表示当前段为代码段

.global _start @声明_start为全局符号

_start: @汇编程序的入口

@ 1.指令:能够编译生成一条32位的机器码,且能被CPU识别和执行

@ 1.1 数据处理指令:数学运算、逻辑运算

@ 数据搬移指令

@ MOV R1, #1

@ R1 = 1

@ MOV R2, R1

@ R2 = R1

@ MVN R0, #0xFF

@ R0 = ~0xFF

@ 立即数

@ 立即数的本质就是包含在指令当中的数,属于指令的一部分

@ 立即数的优点:取指的时候就可以将其读取到CPU,不用单独去内存读取,速度快

@ 立即数的缺点:不能是任意的32位的数字,有局限性

@ MOV R0, #0x12345678

@ MOV R0, #0x12

@ 编译器替换

@ MOV R0, #0xFFFFFFFF

@ 数据运算指令基本格式

@ 《操作码》《目标寄存器》《第一操作寄存器》《第二操作数》

@ 操作码 指示执行哪种运算

@ 目标寄存器: 存储运算结果

@ 第一操作寄存器:第一个参与运算的数据(只能是寄存器)

@ 第二操作数: 第二个参与运算的数据(可以是寄存器或立即数)

@ 加法指令

@ MOV R2, #5

@ MOV R3, #3

@ ADD R1, R2, R3

@ R1 = R2 + R3

@ ADD R1, R2, #5

@ R1 = R2 + 5

@ 减法指令

@ SUB R1, R2, R3

@ R1 = R2 - R3

@ SUB R1, R2, #3

@ R1 = R2 - 3

@ 逆向减法指令

@ RSB R1, R2, #3

@ R1 = 3 - R2

@ 乘法指令

@ MUL R1, R2, R3

@ R1 = R2 * R3

@ 乘法指令只能是两个寄存器相乘

@ 按位与指令

@ AND R1, R2, R3

@ R1 = R2 & R3

@ 按位或指令

@ ORR R1, R2, R3

@ R1 = R2 | R3

@ 按位异或指令

@ EOR R1, R2, R3

@ R1 = R2 ^ R3

@ 左移指令

@ LSL R1, R2, R3

@ R1 = (R2 << R3)

@ 右移指令

@ LSR R1, R2, R3

@ R1 = (R2 >> R3)

@ 位清零指令

@ MOV R2, #0xFF

@ BIC R1, R2, #0x0F

@ 第二操作数中的哪一位为1,就将第一操作寄存器的中哪一位清零,然后将结果写入目标寄存器

@ 格式扩展

@ MOV R2, #3

@ MOV R1, R2, LSL #1

@ R1 = (R2 << 1)

@ 数据运算指令对条件位(N、Z、C、V)的影响

@ 默认情况下数据运算不会对条件位产生影响,在指令后加后缀”S“才可以影响

@ 带进位的加法指令

@ 两个64位的数据做加法运算

@ 第一个数的低32位放在R1

@ 第一个数的高32位放在R2

@ 第二个数的低32位放在R3

@ 第二个数的高32位放在R4

@ 运算结果的低32位放在R5

@ 运算结果的高32位放在R6

@ 第一个数

@ 0x00000001 FFFFFFFF

@ 第二个数

@ 0x00000002 00000005

@ MOV R1, #0xFFFFFFFF

@ MOV R2, #0x00000001

@ MOV R3, #0x00000005

@ MOV R4, #0x00000002

@ ADDS R5, R1, R3

@ ADC R6, R2, R4

@ 本质:R6 = R2 + R4 + 'C'

@ 带借位的减法指令

@ 第一个数

@ 0x00000002 00000001

@ 第二个数

@ 0x00000001 00000005

@ MOV R1, #0x00000001

@ MOV R2, #0x00000002

@ MOV R3, #0x00000005

@ MOV R4, #0x00000001

@ SUBS R5, R1, R3

@ SBC R6, R2, R4

@ 本质:R6 = R2 - R4 - '!C'

@ 1.2 跳转指令:实现程序的跳转,本质就是修改了PC寄存器

@ 方式一:直接修改PC寄存器的值(不建议使用,需要自己计算目标指令的绝对地址)

@ MAIN:

@ MOV R1, #1

@ MOV R2, #2

@ MOV R3, #3

@ MOV PC, #0x18

@ MOV R4, #4

@ MOV R5, #5

@ FUNC:

@ MOV R6, #6

@ MOV R7, #7

@ MOV R8, #8

@ 方式二:不带返回的跳转指令,本质就是将PC寄存器的值修改成跳转标号下指令的地址

@ MAIN:

@ MOV R1, #1

@ MOV R2, #2

@ MOV R3, #3

@ B FUNC

@ MOV R4, #4

@ MOV R5, #5

@ FUNC:

@ MOV R6, #6

@ MOV R7, #7

@ MOV R8, #8

@ 方式三:带返回的跳转指令,本质就是将PC寄存器的值修改成跳转标号下指令的地址,同时将跳转指令下一条指令的地址存储到LR寄存器

@ MAIN:

@ MOV R1, #1

@ MOV R2, #2

@ MOV R3, #3

@ BL FUNC

@ MOV R4, #4

@ MOV R5, #5

@ FUNC:

@ MOV R6, #6

@ MOV R7, #7

@ MOV R8, #8

@ MOV PC, LR

@ 程序返回

@ ARM指令的条件码

@ 比较指令

@ CMP指令的本质就是一条减法指令(SUBS),只是没有将运算结果存入目标寄存器

@ MOV R1, #1

@ MOV R2, #2

@ CMP R1, R2

@ BEQ FUNC

@ 执行逻辑:if(EQ){B FUNC} 本质:if(Z==1){B FUNC}

@ BNE FUNC

@ 执行逻辑:if(NQ){B FUNC} 本质:if(Z==0){B FUNC}

@ MOV R3, #3

@ MOV R4, #4

@ MOV R5, #5

@ FUNC:

@ MOV R6, #6

@ MOV R7, #7

@ ARM指令集中大多数指令都可以带条件码后缀

@ MOV R1, #1

@ MOV R2, #2

@ CMP R1, R2

@ MOVGT R3, #3

@ 练习:用汇编语言实现以下逻辑

@ int R1 = 9;

@ int R2 = 15;

@ START:

@ if(R1 == R2)

@ {

@ STOP();

@ }

@ else if(R1 > R2)

@ {

@ R1 = R1 - R2;

@ goto START;

@ }

@ else

@ {

@ R2 = R2 - R1;

@ goto START;

@ }

@ 练习答案

@ MOV R1, #9

@ MOV R2, #15

@ START:

@ CMP R1,R2

@ BEQ STOP

@ SUBGT R1, R1, R2

@ SUBLT R2, R2, R1

@ B START

@ STOP:

@ B STOP

@ 1.3 Load/Srore指令:访问(读写)内存

@ 写内存

@ MOV R1, #0xFF000000

@ MOV R2, #0x40000000

@ STR R1, [R2]

@ 将R1寄存器中的数据写入到R2指向的内存空间

@ 读内存

@ LDR R3, [R2]

@ 将R2指向的内存空间中的数据读取到R3寄存器

@ 读/写指定的数据类型

@ MOV R1, #0xFFFFFFFF

@ MOV R2, #0x40000000

@ STRB R1, [R2]

@ 将R1寄存器中的数据的Bit[7:0]写入到R2指向的内存空间

@ STRH R1, [R2]

@ 将R1寄存器中的数据的Bit[15:0]写入到R2指向的内存空间

@ STR R1, [R2]

@ 将R1寄存器中的数据的Bit[31:0]写入到R2指向的内存空间

@ LDR指令同样支持以上后缀

@ 寻址方式就是CPU去寻找操作数的方式

@ 立即寻址

@ MOV R1, #1

@ ADD R1, R2, #1

@ 寄存器寻址

@ ADD R1, R2, R3

@ 寄存器移位寻址

@ MOV R1, R2, LSL #1

@ 寄存器间接寻址

@ STR R1, [R2]

@ ...

@ 基址加变址寻址

@ MOV R1, #0xFFFFFFFF

@ MOV R2, #0x40000000

@ MOV R3, #4

@ STR R1, [R2,R3]

@ 将R1寄存器中的数据写入到R2+R3指向的内存空间

@ STR R1, [R2,R3,LSL #1]

@ 将R1寄存器中的数据写入到R2+(R3<<1)指向的内存空间

@ 基址加变址寻址的索引方式

@ 前索引

@ MOV R1, #0xFFFFFFFF

@ MOV R2, #0x40000000

@ STR R1, [R2,#8]

@ 将R1寄存器中的数据写入到R2+8指向的内存空间

@ 后索引

@ MOV R1, #0xFFFFFFFF

@ MOV R2, #0x40000000

@ STR R1, [R2],#8

@ 将R1寄存器中的数据写入到R2指向的内存空间,然后R2自增8

@ 自动索引

@ MOV R1, #0xFFFFFFFF

@ MOV R2, #0x40000000

@ STR R1, [R2,#8]!

@ 将R1寄存器中的数据写入到R2+8指向的内存空间,然后R2自增8

@ 以上寻址方式和索引方式同样适用于LDR

@ 多寄存器内存访问指令

@ MOV R1, #1

@ MOV R2, #2

@ MOV R3, #3

@ MOV R4, #4

@ MOV R11,#0x40000020

@ STM R11,{R1-R4}

@ 将R1-R4寄存器中的数据写入到以R11为起始地址的内存空间中

@ LDM R11,{R6-R9}

@ 将以R11为起始地址的内存空间中的数据读取到R6-R9寄存器中

@ 当寄存器编号不连续时,使用逗号分隔

@ STM R11,{R1,R2,R4}

@ 不管寄存器列表中的顺序如何,存取时永远是低地址对应小编号的寄存器

@ STM R11,{R3,R1,R4,R2}

@ 自动索引照样适用于多寄存器内存访问指令

@ STM R11!,{R1-R4}

@ 多寄存器内存访问指令的寻址方式

@ MOV R1, #1

@ MOV R2, #2

@ MOV R3, #3

@ MOV R4, #4

@ MOV R11,#0x40000020

@ STMIA R11!,{R1-R4}

@ 先存储数据,后增长地址

@ STMIB R11!,{R1-R4}

@ 先增长地址,后存储数据

@ STMDA R11!,{R1-R4}

@ 先存储数据,后递减地址

@ STMDB R11!,{R1-R4}

@ 先递减地址,后存储数据

@ 栈的种类与使用

@ MOV R1, #1

@ MOV R2, #2

@ MOV R3, #3

@ MOV R4, #4

@ MOV R11,#0x40000020

@ STMFD R11!,{R1-R4}

@ LDMFD R11!,{R6-R9}

@ 栈的应用举例

@ 1.叶子函数的调用过程举例

@ 初始化栈指针

@ MOV SP, #0x40000020

@ MIAN:

@ MOV R1, #3

@ MOV R2, #5

@ BL FUNC

@ ADD R3, R1, R2

@ B STOP

@ FUNC:

@ 压栈保护现场

@ STMFD SP!, {R1,R2}

@ MOV R1, #10

@ MOV R2, #20

@ SUB R3, R2, R1

@ 出栈恢复现场

@ LDMFD SP!, {R1,R2}

@ MOV PC, LR

@ 2.非叶子函数的调用过程举例

@ MOV SP, #0x40000020

@ MIAN:

@ MOV R1, #3

@ MOV R2, #5

@ BL FUNC1

@ ADD R3, R1, R2

@ B STOP

@ FUNC1:

@ STMFD SP!, {R1,R2,LR}

@ MOV R1, #10

@ MOV R2, #20

@ BL FUNC2

@ SUB R3, R2, R1

@ LDMFD SP!, {R1,R2,LR}

@ MOV PC, LR

@ FUNC2:

@ STMFD SP!, {R1,R2}

@ MOV R1, #7

@ MOV R2, #8

@ MUL R3, R1, R2

@ LDMFD SP!, {R1,R2}

@ MOV PC, LR

@ 执行叶子函数时不需要对LR压栈保护,执行非叶子函数时需要对LR压栈保护

@ 1.4 状态寄存器传送指令:访问(读写)CPSR寄存器

@ 读CPSR

@ MRS R1, CPSR

@ R1 = CPSR

@ 写CPSR

@ MSR CPSR, #0x10

@ CPSR = 0x10

@ 在USER模式下不能随意修改CPSR,因为USER模式属于非特权模式

@ MSR CPSR, #0xD3

@ 1.5 软中断指令:触发软中断

@ 异常向量表

@ B MAIN

@ B .

@ B SWI_HANDLER

@ B .

@ B .

@ B .

@ B .

@ B .

@ 应用程序

@ MAIN:

@ MOV SP, #0x40000020

@ 初始化SVC模式下的栈指针

@ MSR CPSR, #0x10

@ 切换成USER模式,开启FIQ、IRQ

@ MOV R1, #1

@ MOV R2, #2

@ SWI #1

@ 触发软中断异常

@ ADD R3, R2, R1

@ B STOP

@ 异常处理程序

@ SWI_HANDLER:

@ STMFD SP!,{R1,R2,LR}

@ 压栈保护现场

@ MOV R1, #10

@ MOV R2, #20

@ SUB R3, R2, R1

@ LDMFD SP!,{R1,R2,PC}^

@ 出栈恢复现场

@ 将压入到栈中的LR(返回地址)出栈给PC,实现程序的返回

@ ‘^’表示出栈的同时将SPSR的值传递给CPSR,实现CPU状态的恢复

@ 1.6 协处理器指令:操控协处理器的指令

@ 1.协处理器数据运算指令

@ CDP

@ 2.协处理器存储器访问指令

@ STC 将协处理器中的数据写入到存储器

@ LDC 将存储器中的数据读取到协处理器

@ 3.协处理器寄存器传送指令

@ MRC 将协处理器中寄存器中的数据传送到ARM处理器中的寄存器

@ MCR 将ARM处理器中寄存器中的数据传送到协处理器中的寄存器

@ *****************************************************************

@ 2.伪指令:本身不是指令,编译器可以将其替换成若干条等效指令

@ 空指令

@ NOP

@ 指令

@ LDR R1, [R2]

@ 将R2指向的内存空间中的数据读取到R1寄存器

@ 伪指令

@ LDR R1, =0x12345678

@ R1 = 0x12345678

@ LDR伪指令可以将任意一个32位的数据放到一个寄存器

@ LDR R1, =STOP

@ 将STOP表示的地址写入R1寄存器

@ LDR R1, STOP

@ 将STOP地址中的内容写入R1寄存器

@ *****************************************************************

@ 3.伪操作:不会生成代码,只是在编译之前告诉编译器怎么编译

@ GNU的伪操作一般都以‘.’开头

@ .global symbol

@ 将symbol声明成全局符号

@ .local symbol

@ 将symbol声明成局部符号

@ .equ DATA, 0xFF

@ MOV R1, #DATA

@ .macro FUNC

@ MOV R1, #1

@ MOV R2, #2

@ .endm

@ FUNC

@ .if 0

@ MOV R1, #1

@ MOV R2, #2

@ .endif

@.rept 3

@ MOV R1, #1

@ MOV R2, #2

@.endr

@ .weak symbol

@ 弱化一个符号,即告诉编译器即便没有这个符号也不要报错

@ .weak func

@ B func

@ .word VALUE

@ 在当前地址申请一个字的空间并将其初始化为VALUE

@ MOV R1, #1

@ .word 0xFFFFFFFF

@ MOV R2, #2

@ .byte VALUE

@ 在当前地址申请一个字节的空间并将其初始化为VALUE

@ MOV R1, #1

@ .byte 0xFF

@ .align N

@ 告诉编译器后续的代码2的N次方对其

@ .align 4

@ MOV R2, #2

@ .arm

@ 告诉编译器后续的代码是ARM指令

@ .thumb

@ 告诉编译器后续的代码是Thumb指令

@ .text

@ 定义一个代码段

@ .data

@ 定义一个数据段

@ .space N, VALUE

@ 在当前地址申请N个字节的空间并将其初始化为VALUE

@ MOV R1, #1

@ .space 12, 0x12

@ MOV R2, #2

@ 不同的编译器伪操作的语法不同

@ *****************************************************************

@ C和汇编的混合编程

@ C和汇编的混合编程原则:在哪种语言环境下符合哪种语言的语法规则

@ 1. 在汇编中将C中的函数当做标号处理

@ 2. 在C中将汇编中的标号当做函数处理

@ 3. 在C中内联的汇编当做C的语句来处理

@ 1. 方式一:汇编语言调用(跳转)C语言

@ MOV R1, #1

@ MOV R2, #2

@ BL func_c

@ MOV R3, #3

@ 2. 方式二:C语言调用(跳转)汇编语言

@ .global FUNC_ASM

@ FUNC_ASM:

@ MOV R4, #4

@ MOV R5, #5

@ 3. C内联(内嵌)汇编

@ *****************************************************************

@ ATPCS协议(ARM-THUMB Procedure Call Standard)

@ ATPCS协议主要内容

@ 1.栈的种类

@ 1.1 使用满减栈

@ 2.寄存器的使用

@ 2.1 R15用作程序计数器,不能作其他用途

@ 2.2 R14用作链接寄存器,不能作其他用途

@ 2.3 R13用作栈指针,不能作其他用途

@ 2.4 当函数的参数不多于4个时使用R0-R3传递,当函数的参数多于4个时,多出的部分用栈传递

@ 2.5 函数的返回值使用R0传递

@ 2.6 其它寄存器主要用于存储局部变量

.global STOP

STOP:

B STOP @死循环,防止程序跑飞

.end @汇编程序的结束

### 关于 UniApp 框架推荐资源与教程 #### 1. **Uniapp 官方文档** 官方文档是最权威的学习资料之一,涵盖了从基础概念到高级特性的全方位讲解。对于初学者来说,这是了解 UniApp 架构技术细节的最佳起点[^3]。 #### 2. **《Uniapp 从入门到精通:案例分析与最佳实践》** 该文章提供了系统的知识体系,帮助开发者掌握 Uniapp 的基础知识、实际应用以及开发过程中的最佳实践方法。它不仅适合新手快速上手,也能够为有经验的开发者提供深入的技术指导[^1]。 #### 3. **ThorUI-uniapp 开源项目教程** 这是一个专注于 UI 组件库设计实现的教学材料,基于 ThorUI 提供了一系列实用的功能模块。通过学习此开源项目的具体实现方式,可以更好地理解如何高效构建美观且一致的应用界面[^2]。 #### 4. **跨平台开发利器:UniApp 全面解析与实践指南** 这篇文章按照章节形式详细阐述了 UniApp 的各个方面,包括但不限于其工作原理、技术栈介绍、开发环境配置等内容,并附带丰富的实例演示来辅助说明理论知识点。 以下是几个重要的主题摘选: - **核心特性解析**:解释了跨端运行机制、底层架构组成及其主要功能特点。 - **开发实践指南**:给出了具体的页面编写样例代码,展示了不同设备间 API 调用的方法论。 - **性能优化建议**:针对启动时间缩短、图形绘制效率提升等方面提出了可行策略。 ```javascript // 示例代码片段展示条件编译语法 export default { methods: { showPlatform() { console.log(process.env.UNI_PLATFORM); // 输出当前平台名称 #ifdef APP-PLUS console.log('Running on App'); #endif #ifdef H5 console.log('Running on Web'); #endif } } } ``` #### 5. **其他补充资源** 除了上述提到的内容外,还有许多在线课程视频可供选择,比如 Bilibili 上的一些免费系列讲座;另外 GitHub GitCode 平台上也有不少优质的社区贡献作品值得借鉴研究。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值