网站建设服务合同缴纳印花税吗,网站建设需什么,网站服务器宽带,360建筑网密码忘了目录 ARM汇编语言基础写在前面 1. ARM汇编的分类2. 关于指令集指令集切换Thumb2指令集统一汇编语言#xff08;UAL#xff09;常用汇编指令 3. 汇编格式立即数与伪指令 4. 操作内存的汇编指令LDR#xff1a;从内存加载数据到CPU寄存器STR#xff1a;将数据从寄存器存储到内… 目录 ARM汇编语言基础写在前面 1. ARM汇编的分类2. 关于指令集指令集切换Thumb2指令集统一汇编语言UAL常用汇编指令 3. 汇编格式立即数与伪指令 4. 操作内存的汇编指令LDR从内存加载数据到CPU寄存器STR将数据从寄存器存储到内存LDM从存储器中加载多个数据到寄存器组满增、满减 空增空减 5. 数据处理汇编指令加法指令ADD减法指令SUB:位操作比较 6.跳转指令 ARM汇编语言基础
对于学习汇编我有话说哈我们实际工作中用到的并不多我们学会常用的遇见不会的直接大模型问就可以了通过汇编我们可以体会到数据底层的流动规律写代码自然就会通透更近一步我们要彻底学会RTOS底层的知识也是必不可少的。
写在前面
在CPU的世界里一切外设都被抽象为寄存器或带有地址的内存数据。CPU只关心其内部的16个寄存器以及内存数据外设寄存器虽然物理上与内存不同但在CPU眼中并无区别唯一的差异在于地址空间。 1. ARM汇编的分类
ARM汇编语言大致可以分为以下几类
内存读写用于访问内存数据。运算类执行加法、减法、逻辑运算等。跳转/分支实现程序流程控制。比较类似于高级语言中的if语句。
这些指令组合成指令集构成了ARM汇编语言的核心。 2. 关于指令集
ARM公司发布了两类主要的指令集
ARM指令集32位指令每条指令占用32位。优点是执行效率高但占用空间较大。Thumb指令集16位指令每条指令占用16位。优点是节省空间但执行效率稍低。
在实际应用中
如果需要节省空间优先使用Thumb指令集。如果需要高效执行优先使用ARM指令集。
一个CPU既可以运行Thumb指令也可以运行ARM指令。如何区分当前指令是Thumb还是ARM指令呢程序状态寄存器CPSR中有一位名为“T”当T1时表示当前运行的是Thumb指令。
指令集切换
指令集的切换通过设置PC寄存器的最低位BIT0来实现
调用函数AThumb指令时将PC寄存器的最低位设置为1即PC 函数A地址 (10)。调用函数BARM指令时将PC寄存器的最低位设置为0即PC 函数B地址。
这种切换方式是通过跳转指令如B或BL实现的目标地址的最低位决定了目标函数的指令集模式。在实际开发中通常使用链接器或编译器工具来管理指令集切换而不是手动设置PC寄存器的最低位。
Thumb2指令集
为了简化指令集切换ARM公司引入了Thumb2指令集。Thumb2指令集支持16位和32位指令混合使用允许在同一个指令集中无缝切换指令长度而无需显式切换指令集。编译器通常会自动选择最优的指令长度以平衡代码大小和执行效率。
统一汇编语言UAL
为了简化开发ARM公司推出了统一汇编语言UAL。开发者无需区分ARM、Thumb或Thumb2指令集只需在程序中使用CODE32、CODE16或THUMB指令来指定代码段的指令集类型。
常用汇编指令
在日常工作中常用的ARM汇编指令包括
数据传输MOV、LDR、STR、LDM、STM逻辑运算AND、OR算术运算ADD、SUB跳转B、BL数据定义DCD地址操作ADR、LDR比较CMP 3. 汇编格式
以“数据处理”指令为例UAL汇编格式为
Operation{cond}{S} Rd, Rn, Operand2Operation表示各类汇编指令如ADD、MOV。cond条件码指定指令执行的条件。例如EQ相等、NE不相等、CS无符号大于等于、CC无符号小于等。条件码可以应用于大多数指令但某些指令如LDM和STM不支持条件码。S是否修改程序状态寄存器CPSR。如果指令带有S后缀执行结果会影响CPSR中的条件标志。Rd目标寄存器用于存储运算结果。Rn第一个源操作数。Operand2第二个操作数。
立即数与伪指令
在16位指令中由于指令长度限制立即数直接给出的数值的范围有限。例如MOV R0, #VAL指令中VAL不可能占用全部16位毕竟MOV R0也需要一些位来表示其含义。为此ARM提供了伪指令让编译器自动处理复杂的立即数转换。
例如
MOV R0, #0x12345678 ; 伪指令编译器会自动将其拆分为多条指令实现在ARM指令集中32位指令可以支持更大的立即数范围但仍有限制。伪指令由编译器自动转换为多条指令以实现复杂的立即数加载。 4. 操作内存的汇编指令
LDR从内存加载数据到CPU寄存器
LDR指令用于从内存中加载数据到CPU寄存器。如果不指定数据类型默认为32位数据。LDR支持多种寻址方式包括偏移寻址、基址寻址和后索引寻址等但是实际我们工作中用的的都是相对比较简单的。
例如
LDR R0, [R1] ; 将R1指向的内存地址中的数据加载到R0
LDR R0, [R1, #4] ; 将R14地址中的数据加载到R0
LDRB R0, [R1] ; 加载8位数据到R0
LDRH R0, [R1] ; 加载16位数据到R0STR将数据从寄存器存储到内存
STR指令用于将数据从寄存器存储到内存。STR也支持多种寻址方式。
例如
MOV R0, #0x20000
MOV R1, #0x10
MOV R2, #0x12
STR R2, [R0] ; 将R2的值存储到R0指向的地址
STR R2, [R0, #4] ; 将R2的值存储到R04地址
STR R2, [R0, #8]! ; 将R2的值存储到R08地址并将R0更新为R08
STR R2, [R0, R1] ; 将R2的值存储到R0R1地址
STR R2, [R0, R1, LSL #4] ; 将R2的值存储到R0(R14)地址
STR R2, [R0], #0x20 ; 将R2的值存储到R0地址并将R0更新为R00x20
STRB R2, [R0] ; 存储8位数据到R0指向的地址LDM从存储器中加载多个数据到寄存器组
LDM指令用于批量加载多个寄存器格式为
LDM{addr_mode}{cond} Rn{!}, reglist{^}addr_mode IAIncrement After每次传输后增加基地址默认可省略。IBIncrement Before每次传输前增加基地址仅ARM指令可用。DADecrement After每次传输后减少基地址仅ARM指令可用。DBDecrement Before每次传输前减少基地址。 !表示修改后的基地址会写回Rn寄存器。如果没有!则Rn保持原值。^表示会影响程序状态寄存器CPSR通常在异常处理中使用。 要注意低位置寄存机对应低地址比如R0寄存器属于最低的位置寄存器R15是最高的寄存器。 有个问题为什么需要这么多的addr_mode? 比如我们往栈中写数据的时候有两种情况 1.SP寄存器所指的地址有数据满栈这个时候我们需要先调整地址再写数据。 2.SP寄存器所指的地址没有数据空栈这种情况是先写数据再调整地址。 很明显我们需要不同的行为的需求自然也就要有了多种addr_mode. 满增、满减 空增空减
根据栈指针指向可分为满(Full)/空(Empty) 满SP指向最后一个入栈的数据需要先修改SP再入栈 空SP指向下一个空位置先入栈再修改SP
根据压栈时SP的增长方向可分为增/减 增(Ascending)SP变大 减(Descending)SP变小
组合后就有4种方式 满增、满减 空增空减。
常用的“满减” 入栈时用STMDB也可以用STMFD作用一样注意是先减地址后存内容 出栈时用LDMIA也可以用LDMFD作用一样。先读内容后加地址
下面是几个例子加黑的内容是汇编指令方框内为内存结果 5. 数据处理汇编指令
数据处理汇编指令有很多我们并不需要全部掌握只需要注意关键的几条即可。
加法指令ADD ADD R1, R2, R3 ; R1 R2 R3ADD R1, R2, #0x12 ; R1 R2 0x12减法指令SUB: SUB R1, R2, R3 ; R1 R2 - R3SUB R1, R2, #0x12 ; R1 R2 - 0x12位操作 ; VisUAL里不支持(14)这样的写法写成0x10AND R1, R2, #(14) ; 位与R1 R2 (14)AND R1, R2, R3 ; 位与R1 R2 R3BIC R1, R2, #(14) ; 清除某位R1 R2 ~(14)BIC R1, R2, R3 ; 清除某位R1 R2 ~R3ORR R1, R2, R3比较
关于比较要说明一下CMP的对比结果会储存在状态寄存器里面下面的语句会根据状态寄存器里面的值决定是否执行比如MOVEQ相等时才执行 CMP R0, R1 ; 比较R0-R1的结果 CMP R0, #0x12 ; 比较R0-0x12的结果 TST R0, R1 ; 测试 R0 R1的结果 TST R0, #(14) ; 测试 R0 (14)的结果
6.跳转指令
C程序中函数A调用函数B的实质是什么 void A() { int a 10; B(a); printf(“ok”); } 实质是跳转去执行函数B的代码函数B执行完后还要回到函数A继续执行后面的代码。 对应的汇编指令就是跳转指令要主要凡事有正反跳走了也要知道怎么跳回来所以要保存返回地址。