我们在学习ARM的时候,一般都不用看汇编启动代码,直接使用芯片厂商提供的汇编启动代码,但是要想深入了解ARM内部原理,就必须掌握一定的汇编知识。
我们在前面总结了处理器架构与指令集,那么汇编和处理器架构、指令集有什么关系呢?先看下图:
从上图可以看出,不同的处理器架构、不同指令集合对应不同汇编指令。可以说,一种指令集就对应一种汇编指令,汇编是开发者与计算机交互的接口,
总结一下,汇编语言是指令集构架的机器码一对一的人类可以理解的翻译,是用人类看得懂的语言来描述指令集。否则指令集的机器码都是一堆二进制数字,人类读起来非常麻烦,但汇编是用类似人类语言的方式描述指令集,从而控制不同的处理器按照人们的想法去工作。
对于CPU来说,它只能识别二进制码,那怎么能识别高级语言呢?于是人们开发了编译器,依照如下顺序,将高级语言翻译成二进制码:
可以说,汇编语言就是高级语言和二进制机器码的桥梁。
本文针对ARM架构的芯片讲解其相关的指令集。
工欲善其事,必先利其器,在学习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} |
VisUAL设置基本不需要什么设置,界面也很简单,常用的有设置背景、编码字体与颜色。设置方式如下:
值得注意的是,设置字体大小需要点击回车才能生效。
首选在编辑区写好你要模拟的汇编代码,点击运行按钮就可进行调试。
值得一提的是,VisUAL可以回退运行,在运行完一条指令后,还可以回退到上一条指令,非常的实用。
当代码运行错误,会提示错误信息,点击[Reset],根据提示修改错误的代码。
根据提示修改代码后,点击[Execute],运行结果如下:
运行成功后,不仅可以看到寄存器的情况,还可以快速查内存情况。以上指令的含义后文会详细讲解。
当然啦,VisUAL还提供了内存分析工具,使用功能方法如下。
好了,关于的VisUAL工具的介绍就这些了,后面会结合ARM的具体汇编指令进一步使用VisUAL工具。
首先,我们先看一个简单的汇编程序:
area ff,code,readonly;声明代码段
code32;声明为32位ARM指令
entry;声明程序入口
start
;b指令
;1.b跳转范围+_32Mb+标号
;b start
;b stop
;2.bl子函数调用
;会把预取指令的地址保存在lr(r14)
;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汇编程序用“;”号进行注释。
当然啦,看不懂上面的示例不要紧,后面会在详细介绍。。
一个完整的ARM汇编由两部分组成:声明,实际代码段两部分组成。
1、声明
在一个程序之前先要进行声明:
A.声明代码段:
用AREA指令定义一个段,说明所定义段的相关属性。(说明段的名字,段的属性)
B.声明ARM指令:
用CODE32或CODE16来声明程序为32位ARM指令或是16位Thumb指令。
C.声明程序入口:
用ENTRY指令标识程序的入口点。
注:这3个声明缺一不可。在程序完成后要用END 指令声明程序结束。每一个汇编程序段都必须有一条END指令,指示代码段的结束。
2、段
A.在ARM汇编语言程序中,以程序段为单位组织代码。段是相对独立的指令或数据序列,具有特定的名称。
B.段的分类
__代码__段:代码段的内容为执行代码
数据段 :数据段存放代码运行时需要用到的数据。
注:一个汇编程序至少有一个代码段。如果程序较长时,可以分割为多个代码段和数据段。多个段在程序编译连接时最终形成一个可执行的映像文件。
C.段具有以下的属性
[LABEL] OPERATION [OPERAND] [;COMMENT]
标号域 操作助记符域 操作数域 注释域
1.标号域(LABLE)
A.标号域用来表示指令的地址、变量、过程名、数据的地址和常量。
B.标号是可以自己起名的标识符,语句标号可以是大小写字母混合,通常以字母开头,由字母、数字、下划线等组成。
C.语句标号不能与寄存器名、指令助记符、伪指令(操作)助记符、变量名同名。
D.语句标号必须在一行的开头书写,不能留空格。
2.操作助记符域(OPERATION)
A.操作助记符域可以为指令、伪操作、宏指令或伪指令的助记符。
B.ARM汇编器对大小写敏感,在汇编语言程序设计中,每一条指令的助记符可以全部用大写、或全部用小写,但不允许在一条指令中大、小写混用。
C.所有的指令都不能在行的开头书写,必须在指令的前面有空格,然后再书写指令。
D.指令助记符和后面的操作数或操作寄存器之间必须有空格,不可以在这之间使用逗号。
3.操作数域(OPERAND)
操作数域表示操作的对象,操作数可以是常量、变量、标号、寄存器名或表达式,不同对象之间必须用逗号“,”分开。
基本格式是操作码,后跟可选条件码,可选S (set flags),如下所示
Operation{cond}{S} Rd, Rn, Operand2
1.其中<>中的项是必须的,{}中的项是可选的。
2.opcode 表示指令助记符。
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值保持不变。
4.使用条件码“cond”可以实现高效的逻辑操作,提高代码的效率。
注:如果执行中不表明条件码,默认为无条件(AL)执行。
在汇编语言程序设计中,经常使用各种符号表示变量、常量和地址
A.符号由大小写字母、数字以及下划线组成。
B.符号区分大小写,同名的大、小写符号会被编译器认为是两个不同的符号。
C.符号在其作用范围内必须唯一,即在其作用范围内不可有同名的符号。
D.自定义的符号名不能与系统的保留字相同。
【注】符号名不应与指令或伪指令同名。
1.程序中的变量
2.程序中的常量
ARM汇编程序所支持常量有数字常量,逻辑常量和字符串常量。
3.程序中的变量代换
程序中的变量可通过代换操作取的一个常量。代换操作符为”$”。使用示例:
LCLS S1
LCLS S2;定义局部字符串变量S1和S2
S1 SETS “Test!”
S2 SETS “This is a $ S1”;S2的值为“This is a Test
审核编辑:汤梓红
全部0条评论
快来发表一下你的评论吧 !