Linux 学习(3)ARM汇编基础

GNU汇编语法

GNU 汇编语法适用于所有的架构,并不是 ARM 独享的,GNU 汇编由一系列的语句组成,每行一条语句,每条语句有三个可选部分,如下:

标号

lable : instruction  @comment

lable:是标号,表示地址位置,有些(insrtruction)前有标号、有些没有。
通过标号可以得到指令(insrtruction)的地址,注意lable后面的“:”,任何以“:”结尾的标识符都会识别为一个lable(标号)
insrtruction: 指令,是汇编指令或者伪指令
@: 后面的表示注释
comment: 注释的内容

add:
	MOVS R0,#0X12 @设置R0=0X12

注意!ARM 中的指令、伪指令、伪操作、寄存器名等可以全部使用大写,也可以全部使用小写,但是不能大小写混用

伪操作

可以使用.section伪操作来定义一个段
.text 表示代码段
.data 表示数据段
.bss 未初始化的数据段
.rodata 只读数据段
定义一个段,以段名开始,以下一段名结束或文件结尾结束

.section.tsetsection @定义一个testsection段

.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。

汇编函数

undefined_Handler:
	ldr  r0,=undefined_Handler
	bx r0
SVC_Handler:
	ldr  r0,=SVC_Handler
	bx r0
Prefabort_Handler:
	ldr  r0,=Prefabort_Handler
	bx r0

undefined_Handler: 函数名
ldr r0,=undefined_Handler 函数体
bx r0 函数返回指令,返回语句不是必须的

常用的汇编指令

处理器内部数据传输指令

使用处理器做的最多事情就是在处理器内部来回的传递数据,常见的操作有:
①、将数据从一个寄存器传递到另外一个寄存器。
②、将数据从一个寄存器传递到特殊寄存器,如CPSR 和 SPSR寄存器。
③、将立即数传递到寄存器。
数据传输常用的指令有三个:MOV、MRS 和 MSR,这三个指令的用法如表 7.2.1.1 所示

指令目的描述
MOVR0R1将R1里面的数据复制到R0
MRSROCPSR将特殊寄存器CPSR里面的数据复制到R0中
MSRCPSRR1将R1中的数据复制到特殊寄存器CPSR中

MOV

MOV 指令用于将数据从一个寄存器拷贝到另外一个寄存器中,或者将一个立即数传递到寄存器里面,使用示例如下:

MOV RO,R1      @将寄存器 R1 中的数据传递给 R0,即 R0=R1 
MOV RO,#OX12   @将立即数0x12传递给寄存器R0 

MRS

MRS 指令用于将特殊寄存器(如 CPSR 和 SPSR)中的数据传递给通用寄存器,要读取特殊寄存器的数据只能使用 MRS 指令!使用示例如下:

MRS R0, CPSR @将特殊寄存器 CPSR 里面的数据传递给 R0,即 R0=CPSR 

MSR

MSR 指令和 MRS 刚好相反,MSR 指令用来将普通寄存器的数据传递给特殊寄存器,也就是写特殊寄存器,写特殊寄存器只能使用 MSR,使用示例如下:

MSR CPSR, R0 @R0 中的数据复制到 CPSR 中,即 CPSR=R0 

存储器访问指令

ARM内核不能够直接访问存储器,比如RAM中的数据.IMX6UL中的外设寄存器就是RAM类型的。利用汇编来配置IMX6UL寄存器的时候,需要借助存储器访问指令。

  1. 把要配置的值写入RX中。
  2. 借助存储器访问指令,把RX中的数据写入到IMX6UL寄存器中。
指令描述
LDR Rd,[Rn,#offset]从存储器(RAM)Rn+offset的位置读取数据存放到ARM寄存器Rd
STR Rd,[Rn,#offset]将ARM寄存器Rd的数据写入到存储器(RAM)的Rn+offset的位置

LDR

LDR 加载立即数使用的是“=”,而不是"”#“。最常用的就是读取CPU的寄存器的值。
IMX6UL寄存器GPIO1_GDIR 的地址是 0X0209C004

ldr r0,=0x0209C004  @将寄存器地址 0X0209C004 加载到 R0 中,即 R0=0X0209C004
ldr r1,[r0]			@读取地址 0X0209C004 中的数据到 R1 寄存器中

STR

STR就是将数据写入到存储器(RAM)中,
IMX6UL寄存器GPIO1_GDIR 的地址是 0X0209C004,现在将这个值配置为0x20000002

ldr r0,=0x0209C004  @将寄存器地址 0X0209C004 加载到 R0 中,即 R0=0X0209C004
ldr r1,=0x20000002  @数值 0x20000002 加载到 R1 中,即 R1=0x20000002
str r1,[r0]			@写数据,将R1中的数据写入到R0所保存的地址中去

LDR 和 STR 都是按照字进行读取和写入的,也就是操作的 32 位数据,如果要按照节、半字进行操作的话可以在指令“LDR”后面加上 B 或 H,比如按字节操作的指令就是 LDRB和STRB,按半字操作的指令就是 LDRH 和 STRH。

压栈和出栈指令

当我们在A函数中调用B函数的时候,要想回来的时候,A函数的代码能正常的执行,要在跳转B函数之前,把当前的处理器的状态进行保存(保存R0-R15)这些寄存器。
在进行保存的时候,需要进行压栈的操作,PUSH
在回复现在的时候,需要进行出栈的操作,POP

指令描述
PUSH {reg list}将寄存器列表存入到栈中
POP{reg list}从栈中恢复寄存器列表

将R0~R3和R12这5个寄存器压栈,当前的SP栈指针指向0x80000000,处理器的栈是向下增长的。

PUSH {R0~R3, R12} @ R0~R3R12 压栈

在这里插入图片描述
这个时候SP指针指向了0x7FFFFFFC,这个时候如果在将LR进行压栈。

PUSH {LR} @ LR 进行压栈

将LR压栈以后的图形
在这里插入图片描述
出栈的时候,就是冲栈顶当前SP的位置,开始后入的先出。

POP {LR} @先恢复 LR
POP {R0~R3,R12} @在恢复 R0~R3,R12

还有一种写法“STMFD SP!”“LDMFD SP!”

STMFD SP!,{R0-R3,R12} @R0~R3,R12 入栈
STMFD SP!,{LR}        @LR 入栈

LMDFD SP!,{LR}        @LR 先恢复LR
LMDFD SP!,{R0-R3,R12} @LR 在恢复R0~R3,R12

跳转指令

有多种跳转操作,比如:
①、直接使用跳转指令 B、BL、BX 等。
②、直接向 PC 寄存器里面写入数据。

指令描述
B{label}跳转到lable
BX{RM}间距跳转,跳动存放于Rm中的地址处,并切换指令集
BL{label}跳转到标号地址,并将返回地址保存在LR中
BLX{RM}结合BX和BL的特点,跳转到RM指定地址并将返回地址保存在LR中,切换指令集。

B指令

这是最简单的跳转指令,B 指令会将 PC(R15)寄存器 的值设置为跳转目标, 一旦执行 B 指令,ARM 处理器就会立即跳转到指定的目标地址。如果要调用的函数不会再返回到原来执行处,那就可以用 B 指令,如下示例:

_START:
	LDR SP ,=0X80200000 @设置堆栈指针
	B main 			    @跳转到main函数
	跳转后,会在回来的时候,就要B

BL指令

在跳转前,将在寄存器LR(R14)中保存当前的PC(R15)寄存器的值,因此可以后面,可以通过吧LR中的值,重新加载到PC中,继续跳转前的代码运行。

push {r0,r1}
cps #0x13  @进入到svc模式,
bl system_irqhandler @加载C语言的中断服务函数
cps #0x12  @进入到IRQ模式

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值