ARM汇编语言 - 简介 [一]

发布者:RadiantDreams最新更新时间:2021-03-25 来源: eefocus关键字:ARM  汇编语言  简介 手机看文章 扫描二维码
随时随地手机看文章

说明:本系列文章将主要以ARMv7和ARMv8架构为例,介绍ARM汇编语言的一些基础知识。关于ARM汇编语言的学习,这里我要推荐一本书和一个网站,其中书是由宋岩翻译的《Cortex-M3权威指南》,其文笔风趣幽默,引人入胜,网站则是azeria-labs。当然,ARM官方的Architecture Reference Manual更是重要的参考。


说起与系统结构相关的汇编语言,自然要先介绍该体系结构的寄存器组成。ARMv7相较于同为32位的x86,寄存器的数量要多一些,名称和配置也不尽相同,但两者还是有一个基本的对照关系:

ARMv7-A在设计之初,就有和之前系列的处理器(比如以ARM9系列为代表的ARMv5)兼容的七种处理器模式,后来在向ARMv8过渡的过程中,又增加了"MON"和"HYP"。


为了减少模式切换时的寄存器保存和恢复,同名寄存器在多种模式下各有一份,称为bank register。某些模式会有自己专有的寄存器,比如FIQ就比IRQ多一些寄存器(R8到R12),这样FIQ在进入和退出中断的时候,所需要做的寄存器保存和恢复就可以减少,这也是它比IRQ更"Fast"的原因。

自从ARMv8出现以后,ARM的寄存器就全面进入了64位时代,通用寄存器的数量从13个(R0-R12)变成了30个(X0-X29) ,其名称中的"R"也被"X"所取代了,但为了保持和32位系统的兼容性,每个ARMv8/ARM64通用寄存器都可被当做2个32位寄存器来使用,这样的32位寄存器用"Wn"来表示。

ARMv8支持两种执行状态(execution state),分别是AArch64和AArch32,在AArch64状态下执行的是A64指令集,在AArch32状态下执行的是与ARMv7前向兼容的A32/T32指令集。

A64指令集看起来和前代的指令集差别不大,但其具有更高的编码效率,别看它叫A64就以为它的指令长度是64位的,依然是32位,也就是4个字节。通常一条指令不会占据太多字节,而为了方便流水线的操作,ARM中指令的字节数通常是保持一致的(最多就是T32/Thumb-2这种2字节和4字节混合的指令),都设计成8个字节话的确挺浪费代码空间。

ARMv8中的A32/T32指令集也不是和ARMv7中A32/T32一模一样的,它做了一些改进和增强,如果你使用了这些强化的特性,当然可以获得更好的性能,但是就不能和ARMv7完全兼容了。如果你希望同样的一套汇编代码在ARMv7和ARMv8中都能直接运行,就不能使用这部分额外的特性。


ARM虽说是RISC架构的,但RISC和CISC并不是泾渭分明的,双方都在互相学习,取长补短。现在ARM支持的指令也是越来越多,本系列文章将仅介绍其中的一部分指令。


【数据传送指令】


基础的LDR/STR

在x86架构中,不管是寄存器之间,还是寄存器和内存之间,都可以使用MOV指令,并且直接操作内存单元上的数据是被允许的。


在ARM架构中,寄存器间传送数据的指令依然是MOV,比如"MOV Ra Rb" 就是把Rb里存放的数据传送给Ra,但内存单元上的数据不允许被直接操作,而是必须先放到寄存器中,为此就有了把内存的内容传送到寄存器的指令LDR(Load),以及把寄存器的内容传送回内存的指令STR(Store)。

传送的时候,内存单元的地址存放在一个寄存器中(比如R1),用[R1]表示,"[]"在这里就对应C语言里的"*",表示取地址里的内容。假设R1里存放的是0x200,内存中地址0x200处的内容是0x5,那么"ldr r0, [r1]"就是将0x5放入r0中。

通用寄存器的数量一共就那么多,直接用寄存器的值来获取内存地址的数量实在太有限了,更多的时候,是通过寄存器的值(基址)加上一个偏移/索引(offset/index)来指向内存对应的单元,索引的大小可以由立即数提供,也可以由寄存器存储的值提供:


STR  R0,[R1, #12]  // R0 --> [R1+12]

LDR  R4,[R5, R6]  // R4 <-- [R5+R6]


如果索引对基址的更改发生在数据传输之前,则称为"预索引"(pre-index),传输前后寄存器R1的值都不会改变。

如果索引对基址的更改发生在数据传输之后(注意下图"[]"位置的改变),则称为"后索引"(post-index),传输后寄存器R1的内容将变为加上其原来的值加上索引后的值。"后索引"其实算是一种二合一的指令,比如"str r0, [r1], #12"就等同于"str r0, [r1]"加上"r1 = r1+12"。

好像缺了点什么,没有既更改R1的值为R1+12,同时把*(R1+12)的值送入R0的?不急,这将在本文的后半段给出答案。


LDR和STR后面可以接一些后缀,比如"B", "H"和"W"分别表示从给定的内存地址取1个字节,2个字节和4个字节。

如果一次传送的不是8个字节,那么64位的寄存器是填不满的,为了保持负数的数值不变,这剩余的字节可能就需要进行符号位扩展(Signed),由后缀"S"表示,其配合"W"使用表示只进行低32位空余字节的扩展,配合"X"则表示进行整个64位的符号位扩展:

LDM/STM与三个问题

一个字节一个字节的传送那是“蚂蚁搬家”,如果要复制大批量的数据,效率实在不高,为此ARMv7还提供了用于批量传输的LDM和STM指令,"M"在这里代表Multiple。STM是把多个寄存器的值传送到内存相邻的位置,LDM反之。多个寄存器在ARM汇编语言中用"{}"圈起来,表示待传送的寄存器列表。


比如"STM R0, {R4,R5}" 就表示将R4的值传送到R0指向的内存单元,R5的值传送到下一个内存单元。批量传输其实是存在一个方向问题的,为了区分下一个内存单元是在上一个单元的后面还是前面(地址更大还是更小),需要加上后缀"I"和"D"来分别表示"Increase"和"Decrease"。


还有一个问题,要将R5的值传送到下一个内存单元,需要首先获得这“下一个”内存单元的地址,这就涉及到地址的增减。假设R0的值是0,如果先增加"0"这个值(在32位系统中,一次增加的值是4),再传送R4,那么就是[0x4]=R4, [0x8]=R5;如果是传送完R4后再增加"0"这个值,那么就是[0x0]=R4, [0x4]=R5。所以还需要加上后缀"A"和"B"来分别表示"After"(传送后增加)和"Before"(传送前增加)。


因此,LDM/STM家族一共有"IA", "IB", "DA"和"DB"四个变种(variant),"LDM"和"STM"什么后缀都不接也可以直接使用,但它其实包含一个隐式规则,即默认为"IA",也就是说"LDM"和"STM"其实分别等同于"LDMIA"和"STMIA"。

在函数调用中,进入子函数的时候要用"PUSH"指令,把存储在CPU寄存器中的局部变量/上下文保存到内存的栈中,退出子函数的时候要用"POP"指令,将栈中保存的内容恢复到对应的寄存器中,因为栈通常是自顶向下生长的,所以"PUSH"和"POP"其实可以分别用"STMDB"和"LDMIA"来替代。


STMDB  SP!, {R0-R3,  LR}  <-->  PUSH  {R0-R3, LR}     

LDMIA  SP!, {R0-R3,  PC}  <-->  POP  {R0-R3, PC}


这里出现了一个"!"符号,那就是我们要解决的第三个问题:在增加/减少"SP"表示的这个数值(比如前面假设的"0")的时候,"SP"本身存储的内容是否跟着一起变化?加上"!"就表示在传送过程中"SP"会自增/自减,传送完成后"SP"的值已经不再是传送前的那个值了,不加"!"就是在传送前后保持"SP"的内容不变。"SP"作为stack pointer,在入栈和出栈的时候自然是要移动的,所以这里用了"!"。


"!"是表示寄存器自增/自减的,所以它并不局限于配合LDM/STM使用,如果它用在STR指令中,比如"str r0, [r1, #12]!",就相当于"str r0 [r1, #12]"加上"r1 = r1+12",这也解决了本文前半段介绍LDR/STR指令时留下的那个问题。


新一代的LDP/STP

在ARMv8中,LDM/STM被新一代的指令LDP(Load Pair)和STP(Store Pair)所取代了,LDM/STM对寄存器列表里包含的寄存器数量并没有什么限制,而LDP/STP要求和内存之间传送数据的寄存器不超过2个。因为"PUSH"和"POP"完全可以用LDM/STM表示,所以他俩也被一并干掉了。两代指令的对应关系大概是这样的:


小结一下,本文主要介绍了ARMv7和ARMv8的数据传送指令,并在其中穿插了ARM汇编语言中"[]", "{}", "!"符号的含义和用法。下文将介绍移位、序转和位操作等数据处理指令。

关键字:ARM  汇编语言  简介 引用地址:ARM汇编语言 - 简介 [一]

上一篇:ARM汇编进阶
下一篇:ARM常用的22个概念!

推荐阅读最新更新时间:2024-11-10 10:21

程序状态寄存器和操作指令
在ARM中有个极其重要的寄存器,就是程序状态寄存器 在ARM Architecture Reference Manual手册中,ProgrammersModel的目录下,有Registers子目录 我们介绍CPSR和SPSR CPSR:Current Program Status Register SPSR:Saved Program Status Register CPSR:cpsr在用户级 编程 时用于存储条件码;CPSR包含条件码标志,中断禁止位,当前处理器模式以及其他状态和控制信息。 SPSR:程序状态保存寄存器,用于保存 CPSR 的状态,以便异常返回后恢复异常发生时的工作状态。 对于CPSR只有1
[单片机]
ARM的STRB和LDRB指令分析
一、SDRAM 1、存储结构 SDRAM的内部是一个存储阵列。阵列就如同表格一样,将数据“填”进去。在数据读写时和表格的检索原理一样,先指定一个行(Row),再指定一个列 (Column),我们就可以准确地找到所需要的单元格,这就是内存芯片寻址的基本原理 这个单元格(存储阵列)就叫逻辑 Bank(Logical Bank,下文简称 L-Bank)。 由于技术、成本等原因,不可能只做一个全容量的 L-Bank,而且最重要的是,由于 SDRAM的工作原理限制,单一的 L-Ban k将会造成非常严重的寻址冲突,大幅降低内存效率。所以人们在 SDRAM内部分割成多个 L-Bank,目前基本都是 4个(这也是SDRAM规范中的最高L-B
[单片机]
<font color='red'>ARM</font>的STRB和LDRB指令分析
arm中的宏定义
语法格式如下: MACRO macroname{ $ parameter1, $ parameter, } 其他指令 MEND MACRO伪操作标识宏定义的开始,MEND标识宏定义的结束。用MACRO及MEND定义一段代码,称为宏定义体,这样在程序中就可以通过宏指令多次调用该代码段。 其中, $ label在宏指令被展开时,label会被替换成相应的符号,通常是一个标号。宏定义中的$label是一个可选参数,在一个符号前使用$表示程序被汇编时将使用相应的值来替代$后的符号。 macroname为所定义的宏的名称。 $para
[单片机]
ARM推出全新DynamIQ技术,为人工智能开启无限可能
新闻摘要: • ARM DynamIQ技术是未来ARM Cortex-A处理器的基础 • 借助专用处理器指令和优化库,人工智能运算性能在未来3-5年可提升50倍 • 与片上加速器紧密结合,提升10倍沟通速度,进而加速人工智能和机器学习的运算 • ARM Cortex-A多核处理针对汽车电子、网络和服务器进行了优化 • DynamIQ big.LITTLE提供更高效、更灵活的多核配置 2017年3月21日,中国北京——ARM今天宣布推出全新的DynamIQ技术。作为未来ARM Cortex-A系列处理器的基础,DynamIQ技术代表了多核处理设计行业的转折点,其灵活多样性将重新定义更多类别设备的多核体验,覆盖从端到云的安全、通用平台
[安防电子]
我国移动芯片实现双突破:高通ARM等重新排位
    近年来,在移动互联网发展的强有力带动下,移动智能终端取代PC成为全球集成电路发展的新市场和新动力,2012年全球移动芯片销售额已基本与PC相关芯片持平。移动芯片市场的爆发性增长,催动原有集成电路产业格局被重塑,产业主导者也在不断博弈的过程中易位,ARM崛起成为芯片产业的新领导者,继高通市值超越Intel后,台积电也正逐步向其逼近。     在产业新方向和市场新格局的形成过程中,移动芯片相关设计及制造技术始终保持着快速创新的态势:     从设计的角度来看,基带及射频芯片与移动通信网络发展紧密相关,随着LTE的逐步商用,多网络制式共存的现状使得多频多模成为发展的基本要求,高通业已推出包括全部移动通信制式的28nm六模基带芯片,
[手机便携]
ARM交叉编译环境安装记录
一、什么是ARM交叉编译环境 交叉编译这个概念的出现和流行是和嵌入式系统的广泛发展同步的。我们常用的计算机软件,都需要通过编译的方式,把使用高级计算机语言编写的代码(比如C代码)编译(compile)成计算机可以识别和执行的二进制代码。比如,我们在Windows平台上,可使用Visual C++开发环境,编写程序并编译成可执行程序。这种方式下,我们使用PC平台上的Windows工具开发针对Windows本身的可执行程序,这种编译过程称为native compilation,中文可理解为本机编译。然而,在进行嵌入式系统的开发时,运行程序的目标平台通常具有有限的存储空间和运算能力,比如常见的ARM平台,其一般的静态存储空间大概是16到
[单片机]
ARM Cortex-M7处理器体系结构简介
本文以ST公司的STM32F7为实例来介绍M7体系结构,主要涉及M7存储器模型以及缓冲机制、编程模型、异常模型、处理器两大工作模式以及特权级,对于核心寄存器、内核外设SysTick、MPU、FPU以及系统控制块SCB仅做简单介绍。适用于对MCU+RTOS感兴趣的读者; 参考手册: STM32F7 Series Cortex®-M7 processor programming manual ARM Cortex-M7 Processor Technical Reference Manual ARM Cortex-M7 Devices Generic User Guide 一、指令集类型简单介绍: 在计算机处理器发展史上形
[单片机]
makefile初步制作,arm-linux- (gcc/ld/objcopy/objdump)详解
在linux中输入vi Makefile 来实现创建Makefile文件 注意:命令行前必须加TAB键 例如:将两个文件led.c和crt0.S汇编文件,制作一个Makefile文件 1 1 led.bin : crt0.S led.c 2 2 arm-linux-gcc -c -o crt0.o crt0.c 3 3 arm-linux-gcc -c -o led.o led.c 4 4 arm-linux-ld -Ttext 0x00000000 -g crt0.o led.o -o led_elf 5 5 arm-linux-objcopy -O binary -S led_elf led.bin 6 6 arm
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved