当前位置: 首页 > news >正文

嵌入式ARM架构学习2——汇编

一、处理器工作模式
ARM有7个基本工作模式:

  • User:非特权模式,大部分任务执行在这种模式
  • FIQ:当一个高优先级(fast)中断产生时将会进入这种模式
  • IRQ:当一个低优先级(normal)中断产生时将会进入这种模式
  • Supervisor:当复位或软中断指令执行时将会进入这种模式
  • Abort:当存取异常时将会进入这种模式
  • Undef:当执行未定义指令时会进入这种模式
  • System:便用和User模式相同寄存器集的特权模式

Cortex-A特有模式:

  • Monitor:是为了安全而扩展出的用于执行安全监控代码的模式;

也是一种特权模式

Part1

学习arm汇编的主要目的是为了编写arm启动代码,启动代码启动以后,引导程序到c语言环境下运行。换句话说启动代码的目的是为了在处理器复位以后搭建c语言最基本的需求。因此启动代码的主要任务有:
1、初始化异常向量表;
2、初始化各工作模式的栈指针寄存器;
3、开启arm内核中断允许;
4、将工作模式设置为user模式;
5、完成上述工作后,引导程序进入c语言主函数执行;
因此汇编指令的学习主要是围绕这几个目的展开,主要学习跟上述目的相关的指令。

1.格式
伪操作:它们不是 ARM 处理器实际的指令(如 MOV, ADD 等),而是写给汇编器看的命令,用于指导汇编器如何工作
area reset, code, readonly
code32
entry
end    
area: 这是最重要的一个伪操作,用于定义一个段。程序、数据、堆栈等都需要被组织在不同的段中。
reset: 这是你为这个段起的名字。名字 reset 具有很强的暗示性,通常用于表示复位向量段,即CPU上电或复位后首先执行的第一段代码所在的位置。
code: 指定该段的属性为代码,意味着这个段包含可执行的指令。
readonly: 指定该段的属性为只读。对于代码段来说,这通常是默认且必须的。

    code32: 表示后续指令使用 32位的 ARM 指令集。
thumb: 表示后续指令使用 16位的 Thumb 指令集。
2.指令    
1.mov
MOV{S}<c> <Rd>, #<const>
MOV{S}<c> <Rd>, <Rm>

        MOV instruction                Canonical form
MOV{S} <Rd>, <Rm>, ASR #<n> ASR{S} <Rd>, <Rm>, #<n>
MOV{S} <Rd>, <Rm>, LSL #<n> LSL{S} <Rd>, <Rm>, #<n>
MOV{S} <Rd>, <Rm>, LSR #<n> LSR{S} <Rd>, <Rm>, #<n>
MOV{S} <Rd>, <Rm>, ROR #<n> ROR{S} <Rd>, <Rm>, #<n>
MOV{S} <Rd>, <Rm>, ASR <Rs> ASR{S} <Rd>, <Rm>, <Rs>
MOV{S} <Rd>, <Rm>, LSL <Rs> LSL{S} <Rd>, <Rm>, <Rs>
MOV{S} <Rd>, <Rm>, LSR <Rs> LSR{S} <Rd>, <Rm>, <Rs>
MOV{S} <Rd>, <Rm>, ROR <Rs> ROR{S} <Rd>, <Rm>, <Rs>
MOV{S} <Rd>, <Rm>, RRX         RRX{S} <Rd>, <Rm>
注意    (1)与C语言中的赋值运算对比(左值/右值),利于加深理解
(2)#<n>/<Rs> 取值范围 (0 - 31)
(3)RRX{S}:扩展右移 (不需要移位量)
(4)在计算机中只识别二进制数据,计算机没有有无符号,浮动点等概念;

mov r0, #0x8
mov r1, r0
mov r3, #31

        mov r0 #1
mov r6, r0, lsl #31
mov r7, r0, lsl r3

2.add(加法指令)
立即数作为第二操作数:        ADD{S}<c> <Rd>, <Rn>, #<const>
寄存器作为第二操作数寄存器:    ADD{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
寄存器作为第二操作数移位量:    ADD{S}<c> <Rd>, <Rn>, <Rm>, <type> <Rs>

mov r0, #0x0F
mov r1, #0xF0
mov r2, #1

        add r6, r0, #0xF0
add r7, r0, r1
add r7, r0, r1, lsl #1
add r8, r0, r1, lsl r2
注意    (1){, <shift>} 其中{}代表可选择,“,”表示在使用时需要在Rm后添加“,” shift 移位量(立即数)
(2) add r0, #3, #2 :为什么没有这种形式,C语言int a = 1 + 2; 编译阶段计算, 不需要在机器指令中体现 

3.sub(减法指令)
立即数作为第二操作数:        SUB{S}<c> <Rd>, <Rn>, #<const>
寄存器作为第二操作数寄存器:    SUB{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
寄存器作为第二操作数移位量:    SUB{S}<c> <Rd>, <Rn>, <Rm>, <type> <Rs>

mov r0, #0xFF
mov r1, #0xF0
mov r2, #1

        sub r6, r0, #0xF0
sub r7, r0, r1
sub r7, r0, r1, lsl #1
sub r8, r0, r1, lsl r2

        以上指令都有立即数作为第二操作数的情况,那么什么是立即数呢?
准确的说这里所指的是12位立即数imm12。先说怎么判断某数是不是12位立即数,12位立即数的条件是:
判断标准:把某个数展开成2进制,该数必须存在一种循环右移(偶数位),使得移位后高24位全0,低8位即为有效imm8;
原因:
0000 (rotate)0000 0000(imm8)
N(0-15)        1000 0001
2N(0-30)
4.ldr(加载指令)
LDR<c> <Rt>, <label>
5.sdr(存放指令)

            
6.MVN(按位取反移动指令):
MVN{S}<c> <Rd>, #<const>
MVN{S}<c> <Rd>, <Rm>{, <shift>}
MVN{S}<c> <Rd>, <Rm>, <type> <Rs>

    7.bic(bit clear):指定位置清0
BIC{S}<c> <Rd>, <Rn>, #<const>
BIC{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
BIC{S}<c> <Rd>, <Rn>, <Rm>, <type> <Rs>

mov r0, #0xFFFFFFFF
mov r1, #1
bic r2, r0, r1, lsl    #31
bic r3, r0, #(1 << 31)

8.orr(or):指定位置1
ORR{S}<c> <Rd>, <Rn>, #<const>
ORR{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
ORR{S}<c> <Rd>, <Rn>, <Rm>, <type> <Rs>

mov r0, #0x00
mov r1, #1
mov r2, #31
orrs r6, r0, #0x80000000
orrs r7, r0, #(1 << 31)
orrs r8, r0, r1, lsl #31
orrs r9, r0, r1, lsl r2

9.条件判断标志NZCV
CPSR寄存器中条件判断标志位
N: 符号标志位:上条指令执行结果最高位bit31为1,则 N = 1, 当结果作为有符号解释时为负值;
Z: 零值标志位:上条指令执行结果为0(即bit0 - bit31 均为0),则 Z = 1;
C: 进位标志位:进行无符号解读,如果在加法过程中进位或者减法时没有借位,则为 C = 1,否则 C = 0
V: 溢出标志位:进行有符号解读,是否发生溢出 -2^31 - 2^31-1(两个正数加得负数,两个负数加得正数)
条件码:eq ge gt le lt al(无条件执行)
equal:等于
not equal:不等于

10.cmp(compare):比较指令
CMP<c> <Rn>, #<const>
CMP<c> <Rn>, <Rm>{, <shift>}
CMP<c> <Rn>, <Rm>, <type> <Rs>

cmp r0, r1 <==> subs r0, r1
比较两个数中的最大值
练习:比较获取三个数中最大值

11.b bl bx :(跳转指令)
B<c> <label>
b fun <==> ldr pc, =fun

BL<c> <label>
bl fun

BX<c> <Rm>
bx lr <==> mov pc, lr

Part2

1.循环
(1)循环三要素
循环结束条件
推动循环趋向终结的语句
循环的循环体
(2)do...while(C)
int i = 0;
int sum = 0;
do{
sum += i;
i++;
}while(i <= 100)

mov r0, #0
mov r1, #0
loop
add r1, r1, r0
add r0, r0, #1
cmp r0, #100
ble loop


(3)while(C) for()
int i = 0;
int sum = 0;
while(i <= 100)
{
sum += i;
i++;
}

int sum = 0;
for(int i = 0; i <= 100; i++)
{
sum += i;
}

        mov r0, #0
mov r1, #0
loop
cmp r0, #100
bgt finish
add r1, r1, r0
add r0, r0, #1
b loop    
finish
b finish

2.函数定义及调用
(1)返回值 函数名(形参列表)
{//函数体
代码块
}
(2)pc => lr and lr =>pc

b main              
func
mov r0, #1
mov r1, #2
add r3, r0, r1
bx lr

        main
mov r0, #100
mov r1, #200
bl func
mov r3, #300
(3)保护现场/恢复现场(压栈/弹栈)
问题1:函数被调修改主调寄存器,问题二:函数嵌套时,无法正确返回。
(1)栈类型空增 空减 满增 满减(ARM 2440))画图讲解
空栈: *sp = xxxx        满栈: sp++
sp++                        *sp = xxxx 
增栈: sp += 4           减栈: sp -= 4
(2)栈顶指针寄存器初始化
mov sp, #0x40001000  : 报错非立即数    
ldr sp,    =0x40001000
魔术棒 -> Target->IRAM1:#0x40000000 size:0x1000
(3)保护现场 :stmfd (store(存储) multiple(多个) full(满) decrease(减少))
STMDB<c> <Rn>{!}, <registers>
<Rn>:栈顶指针寄存器
{!},:入栈出栈后,栈顶指针寄存器自减自增
<registers>:入栈出栈的寄存器列表

(4)恢复现场 :ldmfd (load(加载) multiple(多个) full(满) decrease(减少))
LDMFD<c> <Rn>{!}, <registers>
GNU体系 保护现场、恢复现场由主调完成
b main    
func1
mov r0, #10
mov r1, #20
cmp r0, r1
movge r2, r0
movlt r2, r1
bx lr

func0
mov r0, #1
mov r1, #2
add r3, r0, r1
stmfd sp!, {r0-r12, lr}
bl func1
ldmfd sp!, {r0-r12, pc}
;bx lr

            main
ldr sp, =0x40001000
mov r0, #100
mov r1, #200
stmfd sp!, {r0-r12, lr}
bl func0
ldmfd sp!, {r0-r12, lr}
mov r3, #300

            finish
b finish
end    
《《《《《《《《《《《《《《《《《《《《《《《休息》》》》》》》》》》》》》》》》》》》》》》》

(4)在汇编中调用C语言函数
(1) 创建main.c
(2) 声明 extern void c_add(void);
(3) 导入 import c_add; (keil当中要求)
(4) 保护现场 bl函数调用 恢复现场
(5) 解决编译报错:asm.axf: Error: L6238E: start.o(reset) contains invalid call from '~PRES8 (The user did not require code to preserve 8-byte aligment of 8-byte data objects)' function to 'REQ8 (Code was permitted to depend on the 8-byte aligment of 8-byte data items)' function c_add.
asm.axf: Finished: 0 information, 0 warning and 1 error messages.
解决办法:栈对齐伪指令:preserve8 用于确保函数调用时栈指针保持 8 字节对齐
(6) 创建工程自动添加了启动代码报错:
(1)chong建覆盖工程
(2)删除.sct文件
(3)添加 start.s main.c 
(4)重设软件配置
(7) 魔术棒 -> Debug -> Use Simulator->Run to main(取消)
(8) 魔术棒 -> Linker -> Use Memory Layout from Taget Dialog(勾选)
(9) 魔术棒 -> Taget -> ROM1 -> Start: 0x0 Size:0x2000
(10)函数传参:
stmfd sp!, {r0-r12, lr}
mov r0, #1
mov r1, #2
mov r2, #3
mov r3, #4
mov r4, #5
stmfd sp!, {r4}
bl c_add
ldmfd sp!, {r4}
ldmfd sp!, {r0-r12, lr}

(5)在C语言中调用汇编    
(1)导出 export func1;
(2)声明 extern int func1(int a, int b);

(6)修改工作模式
CPSR M域修改
MRS (read):    MRS<c> <Rd>, <spec_reg>
MSR    (writ):    MSR<c> <spec_reg>, #<const>
MSR<c> <spec_reg>, <Rn>
mrs r0, cpsr
bic r0, r0, #(0x1FF << 0)
orr r0, r0, #(0x10 << 0)
mrs cpsr, r0
(7)异常向量表    
软中断异常:swi #7

10、ARM 内核工作模式有哪些,分别是在什么情况下被切换?(同4)

ARM内核(主要指ARMv4-v7架构的经典A/R系列)通常有7种工作模式,主要用于处理异常和提供系统保护。模式的切换主要由硬件自动完成或通过软件指令触发。

模式切换条件/触发场景
用户模式 (User)正常程序执行的非特权模式。应用程序通常运行在此模式下。
系统模式 (System)一种特权模式,与User模式共用寄存器。通过软件直接修改CPSR的模式位进入,用于运行需要特权的操作系统任务。
快速中断模式 (FIQ)当处理器接受一个快速中断 (FIQ) 请求时自动进入,用于处理高速数据传输、紧急事件等。
普通中断模式 (IRQ)当处理器接受一个普通中断 (IRQ) 请求时自动进入,用于处理一般的外设中断。
管理模式 (Supervisor)复位后的默认模式。当执行软件中断指令 (SWI/SVC) 或进行软复位时自动进入。这是操作系统的内核模式。
中止模式 (Abort)当发生内存访问失败时自动进入,例如:- 预取指中止:CPU试图从无效地址取指令。- 数据中止:指令试图访问无效的内存数据地址。
未定义模式 (Undefined)当CPU遇到一条它无法识别(未定义)的指令时自动进入。

Cortex-A特有模式: 8.Monitor:是为了安全而扩展出的用于执行安全监控代码的模式:也是一种特权模式

9.HYP:测试

总结:除了用户模式系统模式,其他5种模式都与特定的异常一一对应。发生异常时,硬件自动切换模式;处理完异常后,通过特定的指令恢复回之前的模式。


11、异常向量表是什么?(同5)

异常向量表是内存中一块固定的、连续的区域,其中存放着各种异常处理程序的入口地址(或跳转到处理程序的指令)。

  • 工作原理:当异常发生时,ARM处理器会自动地、硬连线地根据异常类型,跳转到表中一个固定的偏移地址上。例如,发生复位异常,就跳转到0x00000000;发生IRQ中断,就跳转到0x00000018

  • 核心作用:它是连接硬件异常软件处理程序的桥梁。硬件通过固定机制自动定位处理程序,确保了异常响应的实时性和确定性

  • 典型布局(地址偏移量):

    • 0x00: 复位 (Reset)

    • 0x04: 未定义指令 (Undefined Instruction)

    • 0x08: 软件中断 (SWI/SVC)

    • 0x0C: 预取指中止 (Prefetch Abort)

    • 0x10: 数据中止 (Data Abort)

    • 0x14: 保留 (Reserved)

    • 0x18: IRQ

    • 0x1C: FIQ


12、什么是立即数?如何判断某数是非法是12位立即数?

  • 立即数:是指在指令编码本身中直接包含的操作数。执行时可以直接使用,无需从寄存器或内存中额外读取。

    • 例如:在指令 MOV R0, #0xFF 中,0xFF 就是一个立即数。

  • 判断12位立即数是否合法:ARM指令中的立即数并非完整的32位,而是由一个12位的编码字段(4位旋转值 + 8位立即数) 来表示。一个32位的常数是合法的12位立即数,当且仅当它可以通过以下方式生成:

    一个8位的数值(范围0-255),循环右移偶数位(0, 2, 4, ..., 30)后得到的32位常数。

    判断方法:您可以想象这个数能否被一个“字节+移位”的组合所表示。常见的非法立即数有:

    • 过大的数(如 0x12345678

    • 所有位模式中若出现连续 1 或连续 0 的“块”长度 > 8 位,基本就编不进去,(如 0x00000FFF 是合法的,因为它就是255循环右移0位;而 0x000001FF 很可能是非法的)


13、b, bl, bx 指令的区别是什么?

这三种都是分支(跳转)指令,但用途不同。

指令全称区别与用途
bBranch单纯跳转。将程序计数器PC直接设置为目标地址。不保存返回地址,用于无需返回的跳转,如循环、条件分支。
blBranch with Link带链接的跳转。在跳转之前,自动将下一条指令的地址(返回地址)保存到链接寄存器LR(r14)。用于函数调用,因为函数结束后需要返回到调用处。
bxBranch and eXchange跳转并切换指令集。跳转到目标寄存器中存储的地址。根据目标地址的最低位(bit[0])来决定后续执行ARM指令(T=0)还是Thumb指令(T=1)。用于从ARM代码跳转到Thumb代码,以及函数返回(bx lr)。

简单总结

  • b跳而不返(用于goto,循环)。

  • bl跳而必返(用于调用函数)。

  • bx跳并可换(用于状态切换和间接跳转)。


14、ARM内核采用的栈是哪种栈?

  • 硬件设计:ARM内核的压栈(PUSH)操作硬件上只支持向低地址增长(递减)

  • 栈指针特性:ARM的栈指针SP(r13)指向的是栈顶最后一个被压入的有效数据(满栈)。

因此,ARM内核采用的栈是 满递减栈 (Full Descending Stack, FD)

  • 满 (Full):SP指向栈顶最后一个有效数据。

  • 递减 (Descending):栈向内存低地址方向生长。压栈时SP减小,弹栈时SP增大。

补充:四种栈类型理论模型

栈的增长方向和栈指针(SP)的位置共同定义了栈的类型,共有四种组合:

类型简称增长方向SP指向压栈(PUSH)操作弹栈(POP)操作
满递减FD向低地址最后入栈的数据先减SP,再存数据先取数据,再加SP
空递减ED向低地址下一个空位置先存数据,再减SP先加SP,再取数据
满递增FA向高地址最后入栈的数据先加SP,再存数据先取数据,再减SP
空递增EA向高地址下一个空位置先存数据,再加SP先减SP,再取数据


    


文章转载自:

http://X3gztprV.nytqy.cn
http://ImQF4H7x.nytqy.cn
http://fz2KSRq5.nytqy.cn
http://O8Fse9kQ.nytqy.cn
http://ONRwIj40.nytqy.cn
http://VwSgy2df.nytqy.cn
http://gyg8gRgp.nytqy.cn
http://FX8b2TqW.nytqy.cn
http://oVB8roSE.nytqy.cn
http://KherXQ3M.nytqy.cn
http://dNehAdBb.nytqy.cn
http://IVVw0DLY.nytqy.cn
http://SrG20GLq.nytqy.cn
http://30mYpi4a.nytqy.cn
http://k67J9XhB.nytqy.cn
http://dzni45jt.nytqy.cn
http://AD2IrMBf.nytqy.cn
http://wTrw0dno.nytqy.cn
http://lOxX0LFQ.nytqy.cn
http://rh8rSRLh.nytqy.cn
http://jGZCTlck.nytqy.cn
http://vpm9xU0T.nytqy.cn
http://IrujJZXF.nytqy.cn
http://O5tLF9tP.nytqy.cn
http://A2lfjZpV.nytqy.cn
http://52Yf1PAJ.nytqy.cn
http://Oz0a0xfz.nytqy.cn
http://EXIwaowv.nytqy.cn
http://FnLCIkvI.nytqy.cn
http://HC9CLpzj.nytqy.cn
http://www.dtcms.com/a/373637.html

相关文章:

  • 渗透测试全景解析:从基础概念到实战演练
  • 鸿蒙Next应用UI稳定性故障调试:从崩溃到流畅的实战指南
  • 企智汇施工工程项目管理系统:全生命周期信息化管理解决方案!施工企业管理系统!施工企业项目管理软件!工程项目管理系统!工程项目管理软件!
  • 遥感数据同化方法:集合卡尔曼滤波和变分同化算法
  • mac安装Java开发环境
  • Java网络初识(2):IP地址和端口号,协议,五元组
  • 什么是算法:高效解决问题的逻辑框架
  • EFCore与EF6:ORM技术深度解析
  • 【开题答辩全过程】以 线上“三味书屋”学习平台设计与实现为例,包含答辩的问题和答案
  • iframe引入界面有el-date-picker日期框,点击出现闪退问题处理
  • BP-Adaboost模型
  • 使用redis的发布/订阅(Pub/Sub), 实现消息队列
  • 鸿蒙:更改状态栏、导航栏颜色
  • [数据结构——lesson4.双向链表]
  • 集成学习:从理论到实践的全面解析
  • 机器学习-集成学习
  • 集成学习简介
  • JDK 17、OpenJDK 17、Oracle JDK 17 的说明
  • VM中CentOS 7密码重置
  • 科技信息差(9.8)
  • MATLAB的数值计算(三)曲线拟合与插值
  • 城市脉搏中的“绿色卫士”:当智能科技邂逅城市清洁
  • linux播放视频出现需要MPEG-4 AAC解码器,H.265(Main Profile)解码器,但是没有安装
  • ARM工作模式、汇编学习
  • 【入门级-算法-6、排序算法:选择排序】
  • React state在setInterval里未获取最新值的问题
  • Linux 物理机如何区分 SSD 与 HDD ——以 DELL PERC H730 Mini 为例
  • AP和stage模式差异
  • 支持生成一维条形码Extend .NET
  • 企业级固态硬盘——U.2接口技术