Linux 学习记录53(ARM篇)

这篇具有很好参考价值的文章主要介绍了Linux 学习记录53(ARM篇)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Linux 学习记录53(ARM篇)

Linux 学习记录53(ARM篇),Linux学习记录,linux,学习,arm开发

一、内存读写指令

在下图界面中可以搜索指定的内存地址
Linux 学习记录53(ARM篇),Linux学习记录,linux,学习,arm开发

1. 在C语言中读取内存

例如已知可以访问的地址为:0x12345678

(unsigned int*)0x12345678//将其强制转换为unsigned int类型的地址
*((unsigned int*)0x12345678)//获取0x12345678地址下的数据

2. 指令码及功能

写内存:
1. str:向指定内存中写入一个字的数据
2. strh:向内存中写入半个字的数据
3. strb:向内存中写入一个字节的数据
读内存:
4. ldr:从内存中读取一个字的数据
5. ldrh:从内存中读取半个字的数据
6. ldrb:从内存中读取一个字节的数据

3. 格式

指令码{条件码} 目标寄存器 [目标地址]
例如:
str r1,r0]  将目标寄存器的数值写入到目标地址对应的内存中
ldr r1,[r0]  在目标地址中读取一个字的数据到

4. 使用示例

.text   
.global _start   
_start:
	mov r0,#0x40000000
	mov r1,#0xffffffff
	str r1,[r0] @将r1中的数据写一个字到0x40000000内存中
stop:
    b stop  
.end    

Linux 学习记录53(ARM篇),Linux学习记录,linux,学习,arm开发
Linux 学习记录53(ARM篇),Linux学习记录,linux,学习,arm开发
Linux 学习记录53(ARM篇),Linux学习记录,linux,学习,arm开发

5. 寻址方式

(1. 前索引方式

.text   
.global _start   
_start:
	mov r0,#0x40000000
	mov r1,#0xffffffff
	@前索引方式
	str r1,[r0,#8] @将r1中的数据写一个字到0x40000000+8的内存中
	ldr r2,[r0,#8] @读取r0+8对应的地址内存中的一个字的数据到r2中
stop:
    b stop  
.end  

Linux 学习记录53(ARM篇),Linux学习记录,linux,学习,arm开发
Linux 学习记录53(ARM篇),Linux学习记录,linux,学习,arm开发

(2. 后索引方式

.text   
.global _start   
_start:
	mov r0,#0x40000000
	mov r1,#0xffffffff
	@后索引方式 完成一次存储后r0寄存器会自动偏移8
	str r1,[r0],#8 @将r1中的数据写一个字到0x40000000的内存中
stop:
    b stop  
.end  

Linux 学习记录53(ARM篇),Linux学习记录,linux,学习,arm开发

Linux 学习记录53(ARM篇),Linux学习记录,linux,学习,arm开发

(3. 自动索引

结合了前两者的索引方式

.text   
.global _start   
_start:
	mov r0,#0x40000000
	mov r1,#0xffffffff
	@自动索引方式 完成一次存储后r0寄存器会自动偏移8
	str r1,[r0,#8]! 	@将r1中的数据写一个字到0x40000000+8的内存中
stop:
    b stop  
.end  

Linux 学习记录53(ARM篇),Linux学习记录,linux,学习,arm开发

Linux 学习记录53(ARM篇),Linux学习记录,linux,学习,arm开发

6.批量寄存器操作指令

(1. 操作码

1. stm 写
2. ldm 读

(2. 格式

stm rm,{寄存器列表}:将寄存器列表中每一个寄存器的数值存放到以rm数值为起始地址的内存中
ldm rm,{寄存器列表}:从rm数值为起始地址的内存中 读取指定数量的数据到寄存器列表中每一个寄存器内

解释:
    1.rm:存放操作的内存首地址的寄存器
    2.关于寄存器列表中的寄存器的表达方式:
        如果寄存器列表中寄存器编号连续,可以用-表示范围  {r7-r11}
        如果寄存器列表中寄存器的编号不连续,可以用','分隔 {r7,r8,r9,r10,r11}
    3.无论寄存器列表中的寄存器顺序是什么样的,在操作内存时始终是低地址对应小编号寄存器
        ex:ldm r6,{r11,r10,r9,r7,r8}  虽然列表中寄存器顺序散乱,但是r7是对应最小的地址数值

(3. 使用示例

.text   
.global _start   
_start:

	mov r1,#1
	mov r2,#2
	mov r3,#3
	mov r4,#4
	mov r5,#5
	
	mov r6,#0x40000000
	stm r6,{r1-r5} 	@将r1-r5寄存器的数据批量存放到内存中
	stm r6,{r1,r2,r3,r4,r5} 	@将r1-r5寄存器的数据批量存放到内存中
	ldm r6,{r7-r11} @将内存中的数据批量读取到r7-r1寄存器中
	
stop:
    b stop  
	
.end   

Linux 学习记录53(ARM篇),Linux学习记录,linux,学习,arm开发
Linux 学习记录53(ARM篇),Linux学习记录,linux,学习,arm开发

(4. 地址增长方式

>1 ia后缀

ia后缀:先往指定的寄存器数值为起始地址中存放数据,然后该寄存器数值自动偏移
例:stmia r6!,{r1-r5}

.text   
.global _start   
_start:

	mov r1,#1
	mov r2,#2
	mov r3,#3
	mov r4,#4
	mov r5,#5
	
	mov r6,#0x40000000
	stmia r6!,{r1-r5}
	
stop:
    b stop  
	
.end  

Linux 学习记录53(ARM篇),Linux学习记录,linux,学习,arm开发

>2 ib后缀

ib后缀:先让指定寄存器的数值增大,再存放数据

.text   
.global _start   
_start:

	mov r1,#1
	mov r2,#2
	mov r3,#3
	mov r4,#4
	mov r5,#5
	
	
	mov r6,#0x40000000
	stmib r6!,{r1-r5}
	
stop:
    b stop  
	
.end  

Linux 学习记录53(ARM篇),Linux学习记录,linux,学习,arm开发
Linux 学习记录53(ARM篇),Linux学习记录,linux,学习,arm开发
可以看到是先偏移在存放数据

>3 da后缀

da后缀:先存放后再向小地址偏移

.text   
.global _start   
_start:

	mov r1,#1
	mov r2,#2
	mov r3,#3
	mov r4,#4
	mov r5,#5
	
	
	ldr r6,=0x40000800
	stmda r6!,{r1-r5}
	
stop:
    b stop  
	
.end  

Linux 学习记录53(ARM篇),Linux学习记录,linux,学习,arm开发
Linux 学习记录53(ARM篇),Linux学习记录,linux,学习,arm开发

>4 db后缀

db后缀:先偏移后存放

.text   
.global _start   
_start:

	mov r1,#1
	mov r2,#2
	mov r3,#3
	mov r4,#4
	mov r5,#5
	
	
	ldr r6,=0x40000800
	stmdb r6!,{r1-r5}
	
stop:
    b stop  
	
.end  

Linux 学习记录53(ARM篇),Linux学习记录,linux,学习,arm开发
Linux 学习记录53(ARM篇),Linux学习记录,linux,学习,arm开发
可以看到是先从0800偏移后再存放的数据

二、栈内存的读写

1. 概述

栈指针寄存器(R13 [SP]),sp始终保存栈顶元素的首地址
栈的本质就是一段内存空间,被分出来用于存放一些临时数据,我们可以用过对栈区内存读写来保护现场

2. 栈的类型

1. 增栈:基于栈指针寄存器完成压栈之后,栈指针的数组往地址大的方向增长
2. 减栈:基于栈指针寄存器完成压栈之后,栈指针的数组往地址小的方向增长
3. 空栈:压栈结束后,栈指针寄存器保存的地址内存中没有有效数据(先压栈再增长地址)
4. 满栈:压栈结束后,栈指针寄存器保存的地址内存中存放追后一次压栈的数据(先增长地址,再压栈)

栈的类型可以分为:空增(EA)、空减(ED)、满增(FA)、满减(FD)

ARM处理器默认采用满减栈实现压栈和出栈

3. 满减栈的压栈和出栈实现

.text   
.global _start   
_start:

	mov r1,#1
	mov r2,#2
	mov r3,#3
	mov r4,#4
	mov r5,#5
	
	
	ldr sp,=0x40000800 	@初始化栈
	stmdb sp!,{r1-r5}	@压栈用db
	ldmia sp!,{r7-r11}	@出栈用ia
	
stop:
    b stop  
	
.end  
======================================
采用满减栈特有后缀 "fd"
.text   
.global _start   
_start:

	mov r1,#1
	mov r2,#2
	mov r3,#3
	mov r4,#4
	mov r5,#5
	
	ldr sp,=0x40000800 	@初始化栈
	stmfd sp!,{r1-r5}	@压栈用db
	ldmfd sp!,{r7-r11}	@出栈用ia
	
stop:
    b stop  
	
.end  

Linux 学习记录53(ARM篇),Linux学习记录,linux,学习,arm开发
Linux 学习记录53(ARM篇),Linux学习记录,linux,学习,arm开发

4. 叶子函数和非叶子函数

叶子函数:函数中没有再调用其他函数的函数称为叶子函数

在使用汇编指令跳转时,如果在非叶子函数再次发生跳转时就需要使用通过压栈的方式来对当前函数内现场进行保护,防止数据被覆盖后原有现场被破坏

.text   
.global _start   
    
_start:
    @栈的初始化
    LDR SP,=0X40000800
    b main
main:
    mov r1,#1
    mov r2,#2
    bl fun1
    add r3,r1,r2
    b main
fun1:
@ 压栈 保护现场,非叶子函数内部调用其他函数,lr的数值也会被覆盖,所以需要将它压栈保护
    stmfd sp!,{r1,r2,lr}
    mov r1,#5
    mov r2,#2
    bl fun2
    sub r4,r1,r2
    @出栈恢复现场
    ldmfd sp!,{r1,r2,pc}
    
    
fun2:
    @ 压栈 保护现场
    stmfd sp!,{r1,r2}
    mov r1,#6
    mov r2,#4
    mul r5,r1,r2
    @出栈恢复现场
    ldmfd sp!,{r1,r2}
    mov pc,lr  @函数返回
    
stop:
    b stop   

.end  
    

Linux 学习记录53(ARM篇),Linux学习记录,linux,学习,arm开发

三、状态寄存器CPSR读写指令

1. 指令码及格式

读:
MRS Rd,CPSR:将CPSR寄存器的数值读取到目标寄存器中
写:
MSR cpsr,操作数:将操作数写道CPSR寄存器中

2. 使用示例

从复位模式切换到USER模式

.text   
.global _start   
    
_start:

	mrs r0,cpsr	@读取CPSR寄存器
	bic r0,r0,#0x1F	@低5位清零
	orr r0,r0,#0x10	@给定数值
	msr cpsr,r0		@将修改后的值赋值
    
stop:
    b stop   

.end  

Linux 学习记录53(ARM篇),Linux学习记录,linux,学习,arm开发

3. 注意事项

USER模式作为唯一的非特权模式,我们不能直接修改CPSR的值切换至其他特权模式,为例保护系统
想要从USER模式切换到其他模式,需要特定的异常出现,才能切换到对应的模式

四、软中断指令

1. 概念

从软件层次上模拟的一个中断,用于ARM从工作模式从USER模式切换到特权模式

2. 指令码和格式

swi 中断号
注意:
1. swi是软中断的指令码
2. 中断号是系统中的中断标识,是由24位数据组成的一个立即数

3. ARM异常处理过程分析

(1. ARM异常源以及异常模式

(5种异常模式对应7种异常源)文章来源地址https://www.toymoban.com/news/detail-599258.html

异常模式 异常源 解释
FIQ异常模式 FIQ类型异常源 引发程序进入FIQ模式的异常事件
IRQ异常模式 IRQ类型异常源 引发程序进入IRQ模式的异常事件
SVC异常模式 复位信号 按键复位/上电复位
SVC异常模式 swi软中断指令 swi 软中断号
undef异常模式 未定义异常源 译码器翻译指令时,无法编译成功,指令未定义
abort异常模式 data abort 取数据发生中断
abort异常模式 prefetch abort 取指令发生中断
五种异常工作模式,对应七种异常源
1. 当发生对应类型的异常源时
2. 则处理器会进入到异常的工作模式
3. 执行异常处理程序,完成某个特定的功能
4. 五种异常工作模式,对应七种异常源,异常源优先级
5. 复位的优先级最高

(2. 异常的处理过程分析

**********处理过程*********
保存现场:这个过程是由CPU自动完成(四大步三小步)
1.保存CPSR到SPSR_<MODE>寄存器中
2.修改CPSR寄存器:
    1>修改状态位(T位),切换到ARM状态
    2>根据需要禁止IRQ和FIQ中断位
    3>修改CPSR寄存器中的模式位,切换到对应的异常模式 M[4:0]
3.保存返回地址到LR_<MODE>
4.修改PC指针,指向对应的异常向量表

**************恢复过程***********
1.恢复SPSR_<mode>寄存器中的值,到CPSR寄存器中
2.恢复LR_<mode>寄存器中的值,到PC寄存器中
1)保存现场是CPU自动完成的,当发生异常时,CPU自动完成保存现场过程
2)当修改PC指针,指向异常处理程序的入口时
3)由于异常处理程序的入口地址不固定
4)所以ARM公司设计引入异常向量表

(3. 异常向量表

1.异常向量表是代码段的一块空间,这块空间大小是32字节,被平均分成了8份,每份占用4个字节
2.异常向量表存放7种异常源对应的异常处理函数的跳转指令,有一份保留
3.7种异常源在异常向量表中的位置是固定的,不可以随意更改
4.只需要指定异常向量表的基地址,根据异常源在异常向量表中的偏移地址,就可以确定异常源在异常向量表中的位置
中断向量地址 异常中断类型 异常中断模式 优先级(6最低)
0x0 复位 特权模式(SVC) 1
0x4 未定义的指令 未定义指令中止模式(Undef) 6
0x8 软件中断(SWI) 特权模式(SVC) 6
0x0c 指令预取中止 中止模式 5
0x10 数据访问中止 中止模式 2
0x14 保留 未使用 未使用
0x18 外部中断请求(IRQ) 外部中断(IRQ)模式 4
0x1c 快速中断请求(FIQ) 快速(FIQ)中断模式 3

(4. swi异常处理代码

.text   
.global _start   
    
_start:
    @初始化异常向量表
    b main  @复位异常
    b .      @undef异常
    b do_swi  @软中断异常
    b .    @指令中止
    b .    @数据中止
    b .    @保留
    b .    @IRQ异常
    b .    @FIQ异常
    
main:
    @初始化栈
    LDR SP,=0X40000800
    @切换到USER模式
    MSR CPSR,#0X10
    mov r1,#1
    mov r2,#2
    @触发软中断
    swi 1
    add r3,r1,r2
    b main
do_swi:
@压栈保护现场
    STMFD SP!,{R1,R2,LR}
    mov r1,#3
    mov r2,#5
    mul r4,r1,r2
    @恢复现场返回主程序执行
    LDMFD SP!,{R1,R2,PC}^   @^的作用是修改PC数值的同时将SPSR数值赋值给CPSR
stop:
    b stop   

.end   

到了这里,关于Linux 学习记录53(ARM篇)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Linux 学习记录57(ARM篇)

    通过IO口的电平,产生对应的外部中断,通过外部中断的处理函数完成相应功能 GIC distributor (GICD)是通用中断控制器(GIC)中的一个组件,它负责接收来自外部设备的中断信号,并将这些中断信号分发给对应的处理器核心进行处理。GICD在多核处理器系统中起到了协调和管理中断

    2024年02月15日
    浏览(45)
  • Linux 学习记录58(ARM篇)

    PPI:私有外设中断号:(ID:0~15) SPI:共享外设中断号:(ID:16~31) SGI:软件产生的中断号:(ID:0~287) 总结: GIC层一共管理288个中断号(ID:0 ~ 287),16个SGIS,16个PPIS,256个SPIS 例: 功能:使能CPU 功能:设置GICD层中断使能 该寄存器共有8个(0-8),用于使能GICD层的的288个中断号,每个寄存器

    2024年02月15日
    浏览(43)
  • 记录移植Python3到arm开发板linux系统中

    开发板情况 arm板是公司采购的工控机。主要用来 使用python3解析excel表格处理数据。 配置如下: 配置 版本 cpu imx6dl(armv7架构) 操作系统 linux3.10 python版本 2.7 项目情况 项目中最好使用 python3 。可行的有以下几种方式: 方式 优缺点 可行度 重做文件系统 订制程度比较高,后期增

    2024年02月04日
    浏览(51)
  • ARM+LINUX嵌入式学习路线

    嵌入式学习是一个循序渐进的过程,如果是希望向嵌入式软件方向发展的话,目前最常见的是嵌入式Linux方向,关注这个方向,大概分3个阶段: 1、嵌入式linux上层应用,包括QT的GUI开发 2、嵌入式linux系统开发 3、嵌入式linux驱动开发 嵌入式目前主要面向的几个操作系统是,

    2024年02月02日
    浏览(64)
  • 【Linux下6818开发板(ARM)】硬件空间挂载

    (꒪ꇴ꒪ ),hello我是 祐言 博客主页:C语言基础,Linux基础,软件配置领域博主🌍 快上🚘,一起学习! 送给读者的一句鸡汤🤔: 集中起来的意志可以击穿顽石! 作者水平很有限,如果发现错误,可在评论区指正,感谢🙏         在嵌入式系统开发中,经常需要使用外部硬件

    2024年02月14日
    浏览(42)
  • linux下arm环境启动脚本/etc/init.d/rcS执行命令失败,踩坑记录

    记一次踩坑记录!!! 接触到一个新的系统,需要在这个系统上跑程序,测试的时候,手动执行脚本和程序都没问题,于是将执行命令写入到linux启动脚本/etc/init.d/rcS这个文件中,然后重启,等待程序起来,但是让我意想不到的是,执行到我加的命令的时候,居然报错,找不

    2024年01月21日
    浏览(49)
  • [ARM+Linux] 基于全志h616外设开发笔记

    修改用户密码 配置网络 nmcli dev wifi  命令扫描周围WIFI热点   nmcli dev wifi connect  xxx  password xxx 命令 连接WiFi 查看ip地址的指令: ifconfig ip addr show wlan0 SSH登录         这是企业开发调试必用方式,比串口来说不用接线,前提是接入网络并获得板子IP 地址,且系统做了SSH的

    2023年04月21日
    浏览(44)
  • Rust在linux下交叉编译到arm开发板

    前段时间做了rust交叉编译到arm开发板,如果引入的包有些包含OpenSSL,ring...遇见了很多问题在网上也查阅很多资料,今天抽个时间做个汇总吧。 虚拟机里面安装rust环境,做到交叉编译的时候应该都已经有了,这个地方就不过多说了,网上找一下就有的 首先描述一下我的环境

    2024年02月15日
    浏览(51)
  • 【嵌入式】Linux开发工具arm-linux-gcc安装及使用

    宿主机 执行编译、链接嵌入式软件的计算机 目标机 运行嵌入式软件的硬件平台 “本地”编译器 用来生成在与编译器本身所在的计算机和操作系统(平台)相同的环境下运行的目标代码,例如 Windows 环境生成 Windows 目标代码。 交叉编译器 用来生成在其它平台上运行的目标代

    2024年01月17日
    浏览(60)
  • ARM_Linux的交叉开发以及交叉编译器

    目录 为什么要使用交叉开发 为什么要使用交叉编译 交叉编译器的安装 交叉编译器的使用 交叉开发是指在通用的电脑上吧程序编写,编译,调试好,再下载到嵌入式产品中去运行,对于一些简单的程序的话,直接在电脑上编译调试好即可,但是对于一些需要操作硬件的开发

    2024年01月23日
    浏览(56)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包