汇编语言学习笔记复习用

首先了解栈(stack)和堆(heap)

栈(stack)空间,用于局部变量,函数调时现场保护和返回地址,函数的形参等。

堆(heap)空间,主要用于动态内存分配,也就是说用 malloc,calloc, realloc 等函数分配的变量空间是 在堆上

堆栈指针寄存器

Cortex – M7/M4/M3 处理器拥有 R0-R15 的通用寄存器组。其中 R13 作为堆栈指针 SP。SP 有两 个,但在同一时刻只能有一个可以用。

主堆栈指针(MSP):这是缺省的堆栈指针,它由 OS 内核、异常服务例程以及所有需要特权访问的 应用程序代码来使用。

进程堆栈指针(PSP):用于常规的应用程序代码(不处于异常服务例程中时)。 另外以下两点要注意:

大多数情况下的应用,只需使用指针 MSP,而 PSP 多用于 RTOS 中。

R13 的最低两位被硬线连接到 0,并且总是读出 0,这意味着堆栈总是 4 字节对齐的。

堆栈的基本操作

大部分芯片在上电以后C语言环境还没准备好,C语言中的函数调用涉及到出栈入栈,出栈入栈就要对堆栈进行操作,所谓的堆栈其实就是一段内存,这段内存比较特殊,由 SP 指针访问,SP 指
针指向栈顶。芯片一上电 SP 指针还没有初始化,所以 C 语言没法运行。

汇编语法

  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=
.align    数据字节对齐,比如:.align 4 表示 4字节对齐。 
.end   表示源文件结束。 
.global    定义一个全局符号,格式为:.global symbol,比如:.global _start。 

GNU 汇编同样也支持函数,函数格式如下: 

函数名: 
  函数体 
  返回语句 

GNU 汇编函数返回语句不是必须的,如下代码就是用汇编写的 Cortex-A7 中断服务函数:

/* SVC 中断 */ 
SVC_Handler: 
    ldr r0, =SVC_Handler 
    bx r0 

常用汇编指令 

.equ 

类似#define , 常量符号

.equ NVA 0x10000

.text

声明接下来的代码都是放在text段(链接文件)

.align 4

变量的对齐宽度

.thumb

表示接下来都使用汇编为thumb指令

thumb指令集是arm指令集的一个子集

.syntax unified

统一汇编语法

Cortex-m3为了兼容thumb指令和thumb2指令,使这两种指令可以使用统一的格式,引入了一种叫做"统一汇编语言UAL"的语法机制。简单说来就是我们不用关心我们使用的是thumb指令还是thumb2指令,而是统一使用32位thumb2指令的语法格式书写

.type xxx, %function

声明xxx为一个函数

.type port_start, %function 
port_start: 
     ldr r0, r1

cpsid i

屏蔽可配置的优先级中断, 等同primask = 1

cpsie i

开启可配置的优先级中断, 等同primask = 0

push

压栈

push {r4, r5}

pop

出栈

pop {r4, r5}

ldr

字数据加载指令

ldr r0, =50

ldrb

字节数据加载指令

ldrb r0,[r1]           @将存储器地址为R1的字节数据读入寄存器R0,并将R0的高24位清零。

ldrb r0,[r1,#8]       @将存储器地址为R1+8的字节数据读入寄存器R0,并将R0的高24位清零。

str

字数据存储指令

str r5, [r4]

将r5寄存器中的值存放到r4寄存器地址中,相当于C的 *r4 = r5

strb

字节数据存储指令

add

加法指令

add r1, r1, #1

等同于: r1 = r1 + 1

adds

等同于add指令, 区别会影响到标志寄存器xpsr

sub

减法指令

sub r1, r1, #1

等同于: r1 = r1 - 1

subs

等同于sub指令, 区别会影响到标志寄存器xpsr

mov

一般传送指令

mov r1, #0

等同于:r1 = 0

msr

用于将操作数的内容传送到程序状态寄存器的特定域中, 操作数可以为通用寄存器或立即数

msr primask, #1
msr primask, r1

传送r1值的内容到primask

mrs

用于将程序状态寄存器的内容传送到通用寄存器中

mrs r0, psp  #Process_Stack_Pointer

将psp指针中的内容存放到r0

bx

指令跳转到指定的目标地址中, 目标地址处指令即可是ARM指令也可以是Thumb指令

bx lr

返回子程序

cbz

比较指令,如果为零就转移

orr

用于两个操作数上的逻辑或运算

orr lr, lr, #0x04

lr中的值与立即数0x04相或,结果存储到lr中

stm

类似与str但是它的对象为一组寄存器

stm r0, {r4-r11}

将r4-r11寄存器值保存到r0所指向的内存

ldm

类似与ldr用于加载内存中的数据,但是它的对象为一块内存

ldm r0, {r4-r11}

将r0所指向的内存数据存储到r4-r11

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值