Linux嵌入式学习之Ubuntu入门(五)汇编语法学习

系列文章内容

Linux嵌入式学习之Ubuntu入门(一)基本命令、软件安装、文件结构、编辑器介绍

Linux嵌入式学习之Ubuntu入门(二)磁盘文件介绍及分区、格式化等

Linux嵌入式学习之Ubuntu入门(三)用户、用户组及文件权限

Linux嵌入式学习之Ubuntu入门(四)Makefile

Linux嵌入式学习之Ubuntu入门(五)汇编语法学习

Linux嵌入式学习之Ubuntu入门(六)shell脚本详解



前言

嵌入式的汇编涉及到堆栈,SP指针,以及DDR初始化。

GNU汇编语法

学stm32的时候有一个startup_stm32f10x_hd.s的启动文件,在keil MDK和IAR两个软件下,语法有不同。

ARM汇编编译使用的是GCC编译器,要符合GNU语法。

基本格式

格式:

label: instruction @ comment
  • label 即标号,表示地址位置,可以通过这个标号得到指令的地址。任何以“:”结尾的标识符都会被识别为一个标号。
  • instruction 即指令,也就是汇编指令或伪指令。
  • @符号,表示后面的是注释,也可以使用“/ * ”和 “ * / ”来注释。
  • comment 是注释内容。

指令、伪指令、伪操作、寄存器名可以大写或小写,但不能混用

段定义

系统预定义了一些段名:

  • .text 表示代码段。
  • .data 初始化的数据段。
  • .bss 未初始化的数据段。
  • .rodata 只读数据段。

自己使用.section伪操作定义:

.section .testsection @定义一个 testsetcion 段

伪操作

  • .byte 定义单字节数据,比如.byte 0x12。
  • .short 定义双字节数据,比如.short 0x1234。
  • .long 定义一个 4 字节数据,比如.long 0x12345678。
  • .equ 赋值语句,比如.equ num, 0x12,表示 num=0x12。
  • .align 数据字节对齐,比如: align 4 表示 4 字节对齐。
  • .end 表示源文件结束。
  • .global 定义一个全局符号,比如: .global _start。

例如:

.global _start

_start:
	ldr r0, =0x12 @r0=0x12

.global 是伪操作,表示_start 是一个全局标号,类似 C 语言里面的全局变量

函数

GNU 汇编同样也支持函数,其中返回语句不是必须的。

函数名:
	函数体
	返回语句

例如:

/* 未定义中断 */
Undefined_Handler:
	ldr r0, =Undefined_Handler
	bx r0   @返回指令
/* SVC 中断 */
SVC_Handler:
	ldr r0, =SVC_Handler
	bx r0
/* 预取终止中断 */
PrefAbort_Handler:
	ldr r0, =PrefAbort_Handler
	bx r0

常用的汇编指令

内部数据传输

指令含义
MOV R0, R1将寄存器 R1 中的数据传递给 R0
MOV R0, #0X12将立即数 0X12 传递给 R0 寄存器
MRS R0, CPSR将特殊寄存器 CPSR 里面的数据传递给 R0(MRS 指令用于将特殊寄存器(如 CPSR 和 SPSR)中的数据传递)(读特殊寄存器)
MSR CPSR, R0MSR 指令用来将普通寄存器的数据传递给特殊寄存器(写特殊寄存器)

存储器访问

I.MX6UL 中的寄存器就是 RAM 类型的,用汇编来配置 I.MX6UL 寄存器的时需先将要配置的值写入到 Rx(x=0~12)寄存器中,然后将 Rx 中的数据写入到 I.MX6UL 寄存器中。读取寄存器过程相反。

LDR

从存储加载数据到寄存器 Rx ,或者将一个立即数加载,加载立即数时用“=”

如 I.MX6UL 有个寄存器 GPIO1_GDIR,其地址为 0X0209C004,

1 LDR R0, =0X0209C004 @ R0=0X0209C004
2 LDR R1, [R0] @ 读取地址 0X0209C004 中的数据到 R1 寄存器中
STR

STR 就是将数据写入到存储器中

例如:
配置寄存器 GPIO1_GDIR 的值为 0X20000002

1 LDR R0, =0X0209C004 @ R0=0X0209C004
2 LDR R1, =0X20000002 @ R1=0X20000002
3 STR R1, [R0] @将 R1 的值写入到 R0 所保存的地址中

LDR 和 STR 都是按照字进行读取和写入的,在指令“LDR”后面加上 B 或 H,比如按字节操作的指令就是 LDRB 和STRB,按半字操作的指令就是 LDRH 和 STRH。

指令含义
LDR Rd, [Rn , #offset]从存储器 Rn+offset 的位置读取数据存放到 Rd 中
STR Rd, [Rn, #offset]将 Rd 写入到存储器中的 Rn+offset 位置
压栈和出栈指令

中断和跳转时要保存当前状态:现场保护。与之对应还有恢复现场。(就是保存 R0~R15 这些寄存器值)
压栈的指令为 PUSH,出栈的指令为 POP, 可一次操作多个寄存器数据,利用当前的栈指针 SP 来生成地址。

如:压栈前SP地址指向 0X80000000

PUSH {R0~R3, R12} @将 R0~R3 和 R12 压栈
PUSH {LR} @将 LR 进行压栈

在这里插入图片描述
(0x80000000指向R12,0x7FFFFFFC指向R0)

出栈:

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

PUSH 和 POP 的另外一种写法是“STMFD SP!”和“LDMFD SP!”

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

LDMFD SP!, {LR} @先恢复 LR
LDMFD SP!, {R0~R3, R12} @再恢复 R0~R3, R12

STM和LDM是多存储和多加载,前面 LDR 和 STR每次只能读写存储器中的一个数据。
FD 是 Full Descending 的缩写,即满递减的意思:SP 指向最后一个入栈的数值,堆栈是由高地址向下增长的,编号小的对应低地址,编号高的对应高地址。

跳转指令

可以用指令或者直接向PC寄存器中写入数据。

指令描述
B < label>跳转到 label,如果超过了+/-2KB,可以指定 B.W< label>使用 32 位的跳转指令
BX < Rm>间接跳转,跳转到存放于 Rm 中的地址处,并且切换指令集
BL < label>跳转到标号地址,并将返回地址保存在 LR 中。
BLX < Rm>结合 BX 和 BL 的特点,跳转到 Rm 指定的地址,并将返回地址保存在 LR 中,切换指令集。
B指令

调用的函数不会再返回到原来的执行处

_start:

ldr sp,=0X80200000 @设置栈指针
b main @跳转到 main 函数
BL指令

跳转之前会在寄存器 LR(R14)中保存当前 PC 寄存器值,所以可以通过将 LR 寄存器中的值重新加载到 PC 中来继续从跳转之前的代码处运行。

push {r0, r1} @保存 r0,r1
cps #0x13 @进入 SVC 模式,允许其他中断再次进去

bl system_irqhandler @加载 C 语言中断处理函数到 r2 寄存器中

cps #0x12 @进入 IRQ 模式
pop {r0, r1}
str r0, [r1, #0X10] @中断执行完成,写 EOIR

第 5 行就是执行 C 语言版的中断处理函数,当处理完成以后返回来继续执行下面的程序,所以使用了 BL 指令。

算术运算指令

在这里插入图片描述
(详细见正点原子的驱动开发指南)

逻辑运算指令

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值