ARM汇编入门

描述

我们在学习ARM的时候,一般都不用看汇编启动代码,直接使用芯片厂商提供的汇编启动代码,但是要想深入了解ARM内部原理,就必须掌握一定的汇编知识。

我们在前面总结了处理器架构与指令集,那么汇编和处理器架构、指令集有什么关系呢?先看下图:

芯片

从上图可以看出,不同的处理器架构、不同指令集合对应不同汇编指令。可以说,一种指令集就对应一种汇编指令,汇编是开发者与计算机交互的接口,

总结一下,汇编语言是指令集构架的机器码一对一的人类可以理解的翻译,是用人类看得懂的语言来描述指令集。否则指令集的机器码都是一堆二进制数字,人类读起来非常麻烦,但汇编是用类似人类语言的方式描述指令集,从而控制不同的处理器按照人们的想法去工作。

对于CPU来说,它只能识别二进制码,那怎么能识别高级语言呢?于是人们开发了编译器,依照如下顺序,将高级语言翻译成二进制码:

芯片

可以说,汇编语言就是高级语言和二进制机器码的桥梁。

本文针对ARM架构的芯片讲解其相关的指令集。

1 工具

工欲善其事,必先利其器,在学习ARM汇编之前,我们先准备好学习软件。这里推荐使用的是VisUAL。VisUAL是一款ARM汇编模拟器,支持Windows、Mac OS X和Linux系统。

下载地址:https://salmanarif.bitbucket.io/visual/downloads.html

使用方法:https://salmanarif.bitbucket.io/visual/user_guide/index.html

【注】下载VisUAL需要VPN,如果没有VPN请自行参看后文提示获取。

芯片

VisUAL模拟的ARM板子如下图所示:

芯片

它没有模拟外设,仅仅模拟了CPU、ROM、RAM。红色区域是ROM,不能读不能写,只能运行其中的程序。ROM区域本来可以读的,这是VisUAL的局限。RAM区域可读可写。

VisUAL 支持一小部分 ARM UAL 指令。这些主要是算术、逻辑、加载/存储和分支指令。下面给出了指令语法的简短摘要。有关详细信息和示例,请移步VisUAL关官网。

Summary Opcode Syntax
Move MOV MOV{S}{cond} dest, op1 {, SHIFT_op #expression}
Move Negated MVN MVN{S}{cond} dest, op1 {, SHIFT_op #expression}
Address Load ADR ADR{S}{cond} dest, expression
LDR Psuedo-Instruction LDR LDR{S}{cond} dest, =expression
Add ADD ADD{S}{cond} dest, op1, op2 {, SHIFT_op #expression}
Add with Carry ADC ADC{S}{cond} dest, op1, op2 {, SHIFT_op #expression}
Subtract SUB SUB{S}{cond} dest, op1, op2 {, SHIFT_op #expression}
Subtract with Carry SBC SBC{S}{cond} dest, op1, op2 {, SHIFT_op #expression}
Reverse Subtract RSB RSB{S}{cond} dest, op1, op2 {, SHIFT_op #expression}
Reverse Subtract with Carry RSC RSC{S}{cond} dest, op1, op2 {, SHIFT_op #expression}
Bitwise And AND AND{S}{cond} dest, op1, op2 {, SHIFT_op #expression}
Bitwise Exclusive Or EOR EOR{S}{cond} dest, op1, op2 {, SHIFT_op #expression}
Bitwise Clear BIC BIC{S}{cond} dest, op1, op2 {, SHIFT_op #expression}
Bitwise Or ORR ORR{S}{cond} dest, op1, op2 {, SHIFT_op #expression}
Logical Shift Left LSL LSL{S}{cond} dest, op1, op2
Logical Shift Right LSR LSR{S}{cond} dest, op1, op2
Arithmetic Shift Right ASR ASR{S}{cond} dest, op1, op2
Rotate Right ROR ROR{S}{cond} dest, op1, op2
Rotate Right and Extend RRX RRX{S}{cond} op1, op2
Compare CMP CMP{cond} op1, op2 {, SHIFT_op #expression}
Compare Negated CMN CMN{cond} op1, op2 {, SHIFT_op #expression}
Test Bit(s) Set TST TST{cond} op1, op2 {, SHIFT_op #expression}
Test Equals TEQ TEQ{cond} op1, op2 {, SHIFT_op #expression}
Load Register LDR LDR{B}{cond} dest, [source {, OFFSET}] Offset addressing
**LDR{B}{cond} dest, [source,
OFFSET]! Pre-indexed addressing**
**LDR{B}{cond} dest, [source],
OFFSET Post-indexed addressing**
Store Register STR STR{B}{cond} source, [dest {, OFFSET}] Offset addressing
**STR{B}{cond} source, [dest,
OFFSET]! Pre-indexed addressing**
**STR{B}{cond} source, [dest],
OFFSET Post-indexed addressing**
Load Multiple Registers LDM[dir] LDM[dir]{cond} source, {list of registers}
Store Multiple Registers STM[dir] STM[dir]{cond} dest, {list of registers}
Branch B B{cond} target
Branch with Link BL BL{cond} target
Declare Word(s) in Memory DCD name DCD value_1, value_2, ... value_N
Declare Constant EQU name equ expression
Declare Empty Word(s) in Memory FILL {name} FILL N
N must be a multiple of 4
Stop Emulation END END{cond}

1.1 VisUAL设置

VisUAL设置基本不需要什么设置,界面也很简单,常用的有设置背景、编码字体与颜色。设置方式如下:

芯片

值得注意的是,设置字体大小需要点击回车才能生效。

1.2 VisUAL使用

首选在编辑区写好你要模拟的汇编代码,点击运行按钮就可进行调试。

芯片

值得一提的是,VisUAL可以回退运行,在运行完一条指令后,还可以回退到上一条指令,非常的实用。

当代码运行错误,会提示错误信息,点击[Reset],根据提示修改错误的代码。

芯片

根据提示修改代码后,点击[Execute],运行结果如下:

芯片

运行成功后,不仅可以看到寄存器的情况,还可以快速查内存情况。以上指令的含义后文会详细讲解。

当然啦,VisUAL还提供了内存分析工具,使用功能方法如下。

芯片

好了,关于的VisUAL工具的介绍就这些了,后面会结合ARM的具体汇编指令进一步使用VisUAL工具。

2 ARM汇编编程简介

首先,我们先看一个简单的汇编程序:

area ff,code,readonly;声明代码段
code32;声明为32ARM指令
entry;声明程序入口
start
;b指令
;1.b跳转范围+_32Mb+标号
;b start
;b stop
;2.bl子函数调用
;会把预取指令的地址保存在lrr14)
;3.bx子函数返回
mov r0,#9
mov r1,#15
mov r5,#9
bl func
;int func(int a,int b)
stop
b stop
func
mov r5,#1
loop
cmp r0,r1
beq stop1
subgt r0,r0,r1
sublt r1,r1,r0
b loop
stop1
bx lr
end

可以看出,ARM汇编程序用“;”号进行注释。

当然啦,看不懂上面的示例不要紧,后面会在详细介绍。。

2.1 汇编语言程序格式

一个完整的ARM汇编由两部分组成:声明,实际代码段两部分组成。

1、声明

在一个程序之前先要进行声明:

A.声明代码段:

用AREA指令定义一个段,说明所定义段的相关属性。(说明段的名字,段的属性)

B.声明ARM指令:

用CODE32或CODE16来声明程序为32位ARM指令或是16位Thumb指令。

C.声明程序入口:

用ENTRY指令标识程序的入口点。

注:这3个声明缺一不可。在程序完成后要用END 指令声明程序结束。每一个汇编程序段都必须有一条END指令,指示代码段的结束。

2、段

A.在ARM汇编语言程序中,以程序段为单位组织代码。段是相对独立的指令或数据序列,具有特定的名称。

B.段的分类

__代码__段:代码段的内容为执行代码

数据段 :数据段存放代码运行时需要用到的数据。

注:一个汇编程序至少有一个代码段。如果程序较长时,可以分割为多个代码段和数据段。多个段在程序编译连接时最终形成一个可执行的映像文件。

C.段具有以下的属性

  • READONLY
  • READWRITE

2.2 汇编语言的语句格式

[LABEL] OPERATION [OPERAND] [;COMMENT]

标号域 操作助记符域 操作数域 注释域

1.标号域(LABLE)

A.标号域用来表示指令的地址、变量、过程名、数据的地址和常量。

B.标号是可以自己起名的标识符,语句标号可以是大小写字母混合,通常以字母开头,由字母、数字、下划线等组成。

C.语句标号不能与寄存器名、指令助记符、伪指令(操作)助记符、变量名同名。

D.语句标号必须在一行的开头书写,不能留空格。

2.操作助记符域(OPERATION)

A.操作助记符域可以为指令、伪操作、宏指令或伪指令的助记符。

B.ARM汇编器对大小写敏感,在汇编语言程序设计中,每一条指令的助记符可以全部用大写、或全部用小写,但不允许在一条指令中大、小写混用。

C.所有的指令都不能在行的开头书写,必须在指令的前面有空格,然后再书写指令。

D.指令助记符和后面的操作数或操作寄存器之间必须有空格,不可以在这之间使用逗号。

3.操作数域(OPERAND)

操作数域表示操作的对象,操作数可以是常量、变量、标号、寄存器名或表达式,不同对象之间必须用逗号“,”分开。

2.3 ARM指令集格式

基本格式是操作码,后跟可选条件码,可选S (set flags),如下所示

Operation{cond}{S} Rd, Rn, Operand2

1.其中<>中的项是必须的,{}中的项是可选的。

2.opcode 表示指令助记符。

  • cond:表示执行条件。
  • S:表示是否影响CPSR寄存器的值。
  • Rd:表示目标寄存器。
  • Rn:表示第一个操作数的寄存器。
  • operand2:表示第2个操作数。

3.“operand2”具有如下的形式:

A.#immed_8r:常数表达式

Eg:

MOV R0,#1

ADD R0,R1,#0X0F

B.Rm:寄存器形式。

即在寄存器方式下,操作数即为寄存器的数值。

Eg:

MOV PC,R0

ADD R1,R1,R2

C.Rm,shift:寄存器移位方式。

将寄存器的移位结果作为操作数,当Rm值保持不变。

  • ASR #n:表示算术右移n位。
  • LSR #n:表示逻辑右移n位。
  • ROR #n:表示循环右移n位。
  • RRX #n:带扩展的循环右移n位。
  • LSL #n:逻辑左移n位。

4.使用条件码“cond”可以实现高效的逻辑操作,提高代码的效率。

  • 所有的ARM指令都可以条件执行。
  • Thumb指令只有B(跳转)指令具有条件执行功能。

注:如果执行中不表明条件码,默认为无条件(AL)执行。

2.4 汇编程序中常用的符号

在汇编语言程序设计中,经常使用各种符号表示变量、常量和地址

A.符号由大小写字母、数字以及下划线组成。

B.符号区分大小写,同名的大、小写符号会被编译器认为是两个不同的符号。

C.符号在其作用范围内必须唯一,即在其作用范围内不可有同名的符号。

D.自定义的符号名不能与系统的保留字相同。

【注】符号名不应与指令或伪指令同名。

1.程序中的变量

  • ARM汇编程序所支持的变量有数字变量,逻辑变量和字符串变量
  • 在ARM汇编程序设计中,可使用GBLA,GBLL,GBLS伪定义声明全局变量,使用LCLA,LCLL,LCLS声明局部变量,并可使用SETA,SETL和SETS对其经行初始化。

2.程序中的常量

ARM汇编程序所支持常量有数字常量,逻辑常量和字符串常量。

3.程序中的变量代换

程序中的变量可通过代换操作取的一个常量。代换操作符为”$”。使用示例:

LCLS S1

LCLS S2;定义局部字符串变量S1和S2

S1 SETS “Test!”

S2 SETS “This is a $ S1”;S2的值为“This is a Test
  
审核编辑:汤梓红

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分