ARM-V7架构(二)

news/发布时间2024/5/16 1:29:42
本节主要介绍ARM指令:
 

GNU汇编语法:

GNU 汇编语法适用于所有的架构,并不是 ARM 独享的,GNU 汇编由一系列的语句组成,
每行一条语句,每条语句有三个可选部分,如下:
label:instruction @ comment
label 即标号,表示地址位置,有些指令前面可能会有标号,这样就可以通过这个标号得到指令的地址,标号也可以用来表示数据地址。注意 label 后面的“:”,任何以“:”结尾的标识符都会被识别为一个标号。
instruction 即指令,也就是汇编指令或伪指令。
@符号,表示后面的是注释,就跟 C 语言里面的“/*”和“*/”一样,其实在 GNU 汇编文件中我们也可以使用“/*”和“*/”来注释。
comment 就是注释内容。
比如如下代码:
add: MOVS R0, #0X12 @设置 R0=0X12
上面代码中“add:”就是标号,“MOVS R0,#0X12”就是指令,最后的“@设置 R0=0X12”就是注释。
 
用户可以使用.section 伪操作来定义一个段,汇编系统预定义了一些段名:
.text 表示代码段。
.data 初始化的数据段。
.bss 未初始化的数据段。
.rodata 只读数据段。
我们当然可以自己使用.section 来定义一个段,每个段以段名开始,以下一段名或者文件结尾结束,比如:
.section .testsection @定义一个 testsetcion 段
汇编程序的默认入口标号是_start,不过我们也可以在链接脚本中使用 ENTRY 来指明其它的入口点,下面的代码就是使用_start 作为入口标号:
.global _start _start: ldr r0, =0x12 @r0=0x12
上面代码中.global 是伪操作,表示_start 是一个全局标号,类似 C 语言里面的全局变量一样,常见的伪操作有:
.byte 定义单字节数据,比如.byte 0x12。
.short 定义双字节数据,比如.short 0x1234。
.long 定义一个 4 字节数据,比如.long 0x12345678。
.equ 赋值语句,格式为:.equ 变量名,表达式,比如.equ num, 0x12,表示 num=0x12。
.align 数据字节对齐,比如:.align 4 表示 4 字节对齐。
.end 表示源文件结束。
.global 定义一个全局符号,格式为:.global symbol,比如:.global _start。
 
GNU 汇编同样也支持函数,函数格式如下:
函数名:函数体返回语句
GNU 汇编函数返回语句不是必须的,如下代码就是用汇编写的 Cortex-A7 中断服务函数:
/* 未定义中断 */
Undefined_Handler:ldr r0, =Undefined_Handlerbx r0
/* SVC 中断 */
SVC_Handler:ldr r0, =SVC_Handlerbx r0
/* 预取终止中断 */
PrefAbort_Handler:ldr r0, =PrefAbort_Handler bx r0
上述代码中定义了三个汇编函数:Undefined_Handler、SVC_Handler 和PrefAbort_Handler。以函数 Undefined_Handler 为例我们来看一下汇编函数组成,“Undefined_Handler”就是函数名,“ldr r0, =Undefined_Handler”是函数体,“bx r0”是函数返回语句,“bx”指令是返回指令,函数返回语句不是必须的。
 

ARM-V7常用汇编

处理器内部数据传输指令

MOV指令:
mov指令常见的三种用法:
  • 用于数据传送可以传送立即数,寄存器的值和移位操作产生的值
  • 当目标寄存器是PC指针的时候,可以实现程序的跳转
  • 当目标寄存器是pc指针的时候并且s位被设置,那么在执行跳转操作指令的同时会把SPSR寄存器的值恢复到CPSR中,所用于异常返回
mov r0,r0    /*空指令,耗时操作*/
mov r0,r0,lsl#3    /*左移操作,相当于r0=r0*8*/
mov pc,lr        /*退出到调用者,用于普通函数返回,PC即是R15*/
movs pc,lr        /*退出到调用者并恢复标志位,用于异常函数返回,加s表示影响cpsr,表示恢复到调用之前的位置*/
 
MVN指令:
mvn指令主要完成下面的功能:
  • 向寄存器中传送一个负数
  • 生成位掩码
  • 求一个数的反码
mvn r0,#4    /*r0 = -5,立即数4取反为-5*/
mvn r0,#0    /*r0 = -1*/
 
MRS 指令:
MRS 指令用于将特殊寄存器(如 CPSR 和 SPSR)中的数据传递给通用寄存器,要读取特殊
寄存器的数据只能使用 MRS 指令!使用示例如下:
MRS R0, CPSR  @将特殊寄存器 CPSR 里面的数据传递给 R0,即 R0=CPSR
 
MSR 指令:
MSR 指令和 MRS 刚好相反,MSR 指令用来将普通寄存器的数据传递给特殊寄存器,也就
是写特殊寄存器,写特殊寄存器只能使用 MSR,使用示例如下:
MSR CPSR, R0  @将 R0 中的数据复制到 CPSR 中,即 CPSR=R0
 

存储器访问指令:

LDR 指令:
LDR 主要用于从存储加载数据到寄存器 Rx 中,LDR 也可以将一个立即数加载到寄存器 Rx中,LDR 加载立即数的时候要使用“=”,而不是“#”。
LDR R0, =0X0209C004 @将寄存器地址 0X0209C004 加载到 R0 中,即 R0=0X0209C004
LDR R1, [R0] @读取地址 0X0209C004 中的数据到 R1 寄存器中
 
STR 指令:
LDR 是从存储器读取数据,STR 就是将数据写入到存储器中,
LDR R0, =0X0209C004 @将寄存器地址 0X0209C004 加载到 R0 中,即 R0=0X0209C004
LDR R1, =0X20000002 @R1 保存要写入到寄存器的值,即 R1=0X20000002
STR R1, [R0] @将 R1 中的值写入到 R0 中所保存的地址中

 

压栈出栈指令:

在 A 函数中调用 B 函数,当 B 函数执行完以后再回到 A 函数继续执行。要想再跳回 A 函数以后代码能够接着正常运行,那就必须在跳到 B 函数之前将当前处理器状态保存起来(就是保存 R0~R15 这些寄存器值),当 B 函数执行完成以后再用前面保存的寄存器值恢复R0~R15 即可。保存 R0~R15 寄存器的操作就叫做现场保护,恢复 R0~R15 寄存器的操作就叫做恢复现场。在进行现场保护的时候需要进行压栈(入栈)操作,恢复现场就要进行出栈操作。压栈的指令为 PUSH,出栈的指令为 POP,PUSH 和 POP 是一种多存储和多加载指令,即可以一次操作多个寄存器数据,他们利用当前的栈指针 SP 来生成地址,PUSH 和 POP 的用法如下所示:
PUSH <reg list>   /*将寄存器列表存入栈中*/
POP <reg list>     /*从栈中恢复寄存器列表*/
举例:
要将 R0~R3 和 R12 这 5 个寄存器压栈
PUSH {R0~R3, R12} @将 R0~R3 和 R12 压栈
push和pop的另外一种写法便是stmfd sp!和ldmfd sp!
 

跳转指令:

有多种跳转操作,比如:
①、直接使用跳转指令 B、BL、BX 等。
②、直接向 PC 寄存器里面写入数据。
 
B指令:
这是最简单的跳转指令,B 指令会将 PC 寄存器的值设置为跳转目标地址, 一旦执行 B 指令,ARM 处理器就会立即跳转到指定的目标地址。如果要调用的函数不会再返回到原来的执行处,那就可以用 B 指令,如下示例:
_start:ldr sp,=0X80200000 /*设置栈指针*/b main     /*跳转到 main 函数*/
上述代码就是典型的在汇编中初始化 C 运行环境,然后跳转到 C 文件的 main 函数中运行,上述代码只是初始化了 SP 指针,有些处理器还需要做其他的初始化,比如初始化 DDR 等等。因为跳转到 C 文件以后再也不会回到汇编了,所以在第 4 行使用了 B 指令来完成跳转。
 
BL指令:
BL 指令相比 B 指令,在跳转之前会在寄存器 LR(R14)中保存当前 PC 寄存器值,所以可以通过将 LR 寄存器中的值重新加载到 PC 中来继续从跳转之前的代码处运行,这是子程序调用一个基本但常用的手段。比如 Cortex-A 处理器的 irq 中断服务函数都是汇编写的,主要用汇编来实现现场的保护和恢复、获取中断号等。但是具体的中断处理过程都是 C 函数,所以就会存在汇编中调用 C 函数的问题。而且当 C 语言版本的中断处理函数执行完成以后是需要返回到irq 汇编中断服务函数,因为还要处理其他的工作,一般是恢复现场。这个时候就不能直接使用B 指令了,因为 B 指令一旦跳转就再也不会回来了,这个时候要使用 BL 指令,示例代码如下:
push {r0, r1}             /*保存 r0,r1*/
cps #0x13                 /*进入 SVC 模式,允许其他中断再次进去*/
bl system_irqhandler     /*加载 C 语言中断处理函数到 r2 寄存器中*/
cps #0x12                 /*进入 IRQ 模式*/
pop {r0, r1}         
str r0, [r1, #0X10]     /*中断执行完成,写 EOIR*/
 

算术运算和逻辑运算指令:

ADD指令:
add r0,r0,#3    /*保留r0中的0位和1位,丢弃其他的位*/
add r2,r1,r3    /*r2 = r1&r3*/
ands r0,r0,#0x01    /*r0 = r0&0x1,取出最低位数据*/
 
ORR指令:
逻辑或
 
SUB指令:
sub r0,r1,r2        /*r0 = r1-r2*/
sub r0,r1,#256      /*r0 = r1-256*/
其他的不一一说明,具体逻辑运算指令如下:
0
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ulsteruni.cn/article/31158570.html

如若内容造成侵权/违法违规/事实不符,请联系编程大学网进行投诉反馈email:xxxxxxxx@qq.com,一经查实,立即删除!

相关文章

ARM-V7架构(一)

cortex-A7基于ARMV7-A架构,复习一下armv7ARM-V7的模式类型如下:FIQ快速中断和IRQ外部中断的区别:当一个高优先级中断产生时将会进入FIQ,一般用于高速数据传输和通道处理。当一个低优先级中断产生将会进入IRQ,一般用于通常的中断处理 处理器模式可以通过软件控制进行切换,…

NOIP 2024游记,我附中

日记碎了一地……前言 作者真的去了 NOIP2024,但本文纯属虚构。 赛前 Day -1 下午 已是 NOIP2024 前的最后一天,可当我上台讲题时,脑袋里满是眩晕的感觉,大概嘴唇发白,已经站在死亡的边缘了。 子洢 [Note 1],子洢,我好像再也见不到我的姐姐了。多希望她能陪在我身边啊。…

Linux环境下Minio的安装部署与启动教程(完整版)

1、概述 MinIO是一个开源、分布式的对象存储系统,专为云原生环境设计。它提供了一个基于标准的Amazon S3兼容接口,使得开发者可以使用熟悉的API在私有云或边缘环境中部署和管理大规模非结构化数据,如图片、视频、日志文件等。 MinIO的核心特点包括: 高性能:采用Golang编写…

人人都是艺术家!AI工具Doodly让潦草手绘变精美画作

AI绘画界太卷了,一天一个新东西,不久前刚给大家介绍了可以一秒出图的SDXL-Turbo,今天来聊一聊另一位重磅选手Doodly有用过Stable Diffuison的小伙伴都知道,想要生成一张高质量的图片,需要输入非常详细的提示词,并伴随多次“摇色子”才能获得满意的结果,有没有简便的方法…