专栏首页电子技术研习社arm(2)| 汇编指令和伪指令

arm(2)| 汇编指令和伪指令

今天我们来说一下arm的汇编指令和伪指令。

一、指令和伪指令

我们首先来了解一下什么叫做指令和伪指令。

指令是CPU机器指令的助记符,经过编译后会得到一串10组成的机器码,可以由CPU读取执行。伪指令本质上不是指令(只是和指令一起写在代码中),它是编译器环境提供的,目的是用来指导编译过程,经过编译后伪指令最终不会生成机器码。所以指令和伪指令最大区别就是编译完之后会不会生成机器码。

arm汇编有两种风格,ARM官方的ARM汇编风格:指令一般用大写、Windows中IDE开发环境(如ADS、MDK等)常用。如:LDR R0, [R1]。GNU风格的ARM汇编:指令一般用小写字母、linux中常用。如:ldr r0, [r1]。

二、arm汇编特点

ARM汇编特点1:LDR/STR架构。ARM采用RISC架构,CPU本身不能直接读取内存,而需要先将内存中内容加载入CPU中通用寄存器中才能被CPU处理。ldr(load register)指令将内存内容加载入通用寄存器。str(store register)指令将寄存器内容存入内存空间中。ldr/str组合用来实现 ARM CPU和内存数据交换。

ARM汇编特点2:8种寻址方式

寄存器寻址 mov r1, r2

立即寻址 mov r0, #0xFF00

寄存器移位寻址 mov r0, r1, lsl #3

寄存器间接寻址 ldr r1, [r2]

基址变址寻址 ldr r1, [r2, #4]

多寄存器寻址 ldmia r1!, {r2-r7,r12}

堆栈寻址 stmfd sp!, {r2-r7,lr}

相对寻址 beqflag

ARM汇编特点3:指令后缀。同一指令经常附带不同后缀,变成不同的指令。经常使用的后缀有:

B(byte)功能不变,操作长度变为8位

H(half word)功能不变,长度变为16位

S(signed)功能不变,操作数变为有符号,如 ldr ldrb ldrh ldrsb ldrsh

S(S标志)功能不变,影响CPSR标志位,如 mov和movs movs r0, #0

ARM汇编特点5:多级指令流水线。为增加处理器指令流的速度,ARM使用多级流水线。所以要注意PC指向正被取指的指令,而非正在执行的指令。

三、常用指令

接下来介绍几个常用的指令,对于不常用的指令就不多说了,请自行搜索。

1、mov和mvn

mov r1, r0 把r0寄存器的值加载到r1当中。

mov r1, #0xff 将立即数的值赋给r1。

mov指令是最简单也是最重要的指令了,mvn用法和mov一样,区别在于mov是原封不动的传递,而mvn是按位取反后传递。

2、几个逻辑运算指令

and 逻辑与

orr 逻辑或

eor 逻辑异或

bic 位清除指令

例:bic r0,r1,#0x1f @将r1中的数的bit0到bit4清零后赋值给r0。

3、比较指令cmp

cmp r0, r1 比较r0和r1寄存器值是否相等,若相等,会改变cpsr寄存器对应的零标志位。

4、cpsr访问指令

mrs用来读cpsr或spsr,msr用来写cpsr或spsr

5、跳转指令b、bl、bx

b 直接跳转(就没打开算返回)。

bl branch and link,跳转前把返回地址放入lr中,以便返回,以便用于函数调用。

bx跳转同时切换到ARM模式,一般用于异常处理的跳转。

6、访存指令

ldr/str每周期只能访问4字节内存,如果需要批量读取、写入内存时太慢,解决方案是stm/ldm

关于这一部分内容可以参考https://blog.csdn.net/u013477200/article/details/50723555

这里重点提一下LDM指令和STM指令以及一些后缀。

LDM指令:

LDM指令是LDR指令的“升级”,其实就是加载多个字节到寄存器当中。虽然貌似是LDR的升级,但是,千万要注意,这个指令运行的方向和LDR是不一样的,是从左到右运行的。该指令是将内存中堆栈内的数据,批量的赋值给寄存器,即是出栈操作;其中堆栈指针一般对应于SP,注意SP是寄存器R13,实际用到的却是R13中的内存地址,只是该指令没有写为[R13]。

LDMFD SP! , {R0, R1, R2}

实际上可以理解为: LDMFD [SP]!, {R0, R1, R2}

意思为:把sp指向的3个连续地址段(应该是3*4=12字节(因为为r0,r1,r2都是32位))中的数据拷贝到r0,r1,r2这3个寄存器中去。

STM指令:

S的含义仍然是STORE,与LDM是配对使用的,其指令格式上也相似,即区别于STR,是将堆栈指针写在左边,而把寄存器组写在右边。

STMFD SP!, {R0}

同样的,该指令也可理解为: STMFD [SP]!, {R0}

意思是:把R0保存到堆栈(sp指向的地址)中。

这个可能不是很难理解,同时也注意到在指令后面有一个后缀FD,FD的意思是满栈递减,其实还有另外几个类似的后缀。这里我们需要想了解一下几种栈。

空栈:栈指针指向空位,每次存入时可以直接存入然后栈指针移动一格;而取出时需要先移动一格才能取出。

满栈:栈指针指向栈中最后一格数据,每次存入时需要先移动栈指针一格再存入;取出时可以直接取出,然后再移动栈指针。

增栈:栈指针移动时向地址增加的方向移动的栈。

减栈:栈指针移动时向地址减小的方向移动的栈。

这些不同的栈对应着要使用不同的指令后缀。

ia(increase after)先传输,再地址+4

ib(increase before)先地址+4,再传输

da(decrease after)先传输,再地址-4

db(decrease before)先地址-4,再传输

fd(full decrease)满递减堆栈

ed(empty decrease)空递减堆栈

fa(·······) 满递增堆栈

ea(·······)空递增堆栈

操作栈时使用相同的后缀就不会出错,不管是满栈还是空栈、增栈还是减栈。比如上面我们提到的STMFD和LDMFD,当使用STMFD时,SP指针会先向地址减小方向移动一格(四个字节),再把寄存器的值放进SP所指向的地址当中,因为SP指向的地址里面原本就是满的,当然要移动完之后才能放进去。而使用LDMFD时,就会直接从SP指向的地址把数据加载进寄存器当中,而不需要先移动一格,因为它里面本来就有内容,当然不需要移动了。其他的也是类似的操作,入栈和出栈采用相同的后缀就不会出错。最常见的是stmia和stmfd。

!的作用:

ldmia r0, {r2 - r3}

ldmia r0!, {r2 - r3}

感叹号的作用就是r0的值在ldm过程中发生的增加或者减少最后写回到r0去,也就是说ldm时会改变r0的值。

^的作用

ldmfd sp!, {r0 - r6, pc}

ldmfd sp!, {r0 - r6, pc}^

^的作用:在目标寄存器中有pc时,会同时将spsr写入到cpsr,一般用于从异常模式返回。

那么arm汇编指令就暂时介绍这几个,接下来介绍几个伪指令。

伪指令不是指令,伪指令和指令的根本区别是经过编译后会不会生成机器码。伪指令的意义在于指导编译过程。

ldr 大范围的地址加载指令

adr 小范围的地址加载指令

adrl 中等范围的地址加载指令

nop 空操作

ldr伪指令和ldr指令虽然名字一样,但是还是有区别的,这里涉及到合法立即数和非法立即数的概念。这一部分内容可以参考https://blog.csdn.net/wwwlyj123321/article/details/80802770

简言之,就是ldr指令只能操作合法立即数,ldr伪指令就没有这个限制,所以,我们通常使用的都是ldr伪指令。在写法上,ldr伪指令后面多一个等号,如:LDR R1,=0xFFF

总结:掌握一些常见的指令有助于我们看懂程序,并且进行简单的修改,对于arm汇编,通常只要能大概看懂就行,或者进行一些简单的修改,并不需要完全自己来写。

本文分享自微信公众号 - 电子技术研习社(zjf18770701843),作者:小小飞飞哥

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-04-27

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Linux笔记(10)| 进程概述

    父进程返回正整数,子进程返回0,在执行fork函数之前,操作系统只有一个进程,fork函数之前的,代码只会被执行一次,在执行fork函数之后,操作系统有两个几乎...

    飞哥
  • 小实验 | 利用信号量实现跑马灯

    上一次我们说到了uCOS中的信号量,信号量具有同步的作用,今天做一个小实验来说明这个。

    飞哥
  • 单片机通信之SPI通信

    之前已经给大家介绍过了单片机的UART通信和IIC通信,大家可以点击“利用IIC协议实现单片机对EEPROM的读和写操作”、“单片机通信之串口通信”进行回顾。那...

    飞哥
  • 计算机组成原理笔记(二)

    我们先来看一个问题,在Chrome浏览器里面通过开发者工具,打开浏览器里的Console,在里面输入“0.3 + 0.6”:

    luozhiyun
  • Linux-Bash指令

    悠扬前奏
  • 处理器并行设计

    233333
  • X86 Assemble指令--REP指令前缀簇

    重复N次字符串指令,N的值存储在(E)CX计数寄存器中,或者直到ZF标志位不满足为止。 REP指令前缀簇有如下指令:

    None_Ling
  • 流水线、超流水线、超标量(superscalar)技术对比

    本文转载自:https://blog.csdn.net/qq_32092885/article/details/83349275

    zy010101
  • 流水线、超流水线、超标量(superscalar)技术对比(转)

    流水线技术是一种将每条指令分解为多步,并让各步操作重叠,从而实现几条指令并行处理的技术。程序中的指令仍是一条条顺序执行,但可以预先取若干条指令,并在当前指令尚未...

    zy010101
  • 8086cpu中的标志寄存器与比较指令

    在8086CPU中有一个特殊的寄存器——标志寄存器,该寄存器不同于其他寄存器,普通寄存器是用来存放数据的读取整个寄存器具有一定的含义,但是标志寄存器是每一位都有...

    Masimaro

扫码关注云+社区

领取腾讯云代金券