伪指令作用:
简单的指令拼凑起来,会很难理解,用伪指令可以简化代码结构。就如JAVA中的宏意义一样。例如有一段循环代码,我们可以定义一个常量表示。方便更好的实现程序逻辑。注意:只是在汇编器之前起作用,汇编之后,会翻译为标准的汇编指令集。
Arm汇编伪指令和GNU伪指令是有差别的。
http://blog.chinaunix.net/uid-13701930-id-336459.html
AREA
1、 AREA
语法格式:
AREA 段名 属性1,属性2,……
AREA伪指令用于定义一个代码段或数据段。其中,段名若以数字开头,则该段名需用“|”括起来,如|1_test|。
属性字段表示该代码段(或数据段)的相关属性,多个属性用逗号分隔。常用的属性如下:
— CODE属性:用于定义代码段,默认为READONLY。
— DATA属性:用于定义数据段,默认为READWRITE。
— READONLY属性:指定本段为只读,代码段默认为READONLY。
— READWRITE属性:指定本段为可读可写,数据段的默认属性为READWRITE。
— ALIGN属性:使用方式为ALIGN 表达式。在默认时,ELF(可执行连接文件)的代码段和数据段是按字对齐的,表达式的取值范围为0~31,相应的对齐方式为2表达式次方。
— COMMON属性:该属性定义一个通用的段,不包含任何的用户代码和数据。各源文件中同名的COMMON段共享同一段存储单元。
一个汇编语言程序至少要包含一个段,当程序太长时,也可以将程序分为多个代码段和数据段。
使用示例:
AREA Init,CODE,READONLY
EQU——常量声明
类似#define,用法:UARTCON EQU 0x3FFD000
表示UARTCON 和 0x3FFD000等效
参考注意事项.wps,伪指令要顶头书写,不然识别不了。
EXPORT——可用GLOBAL代替,GNU汇编中直接就是.global表示。意思是这段代码可以被全局使用。
EXPORT HELLO
HELLO
MOV R1,R2
对比GNU汇编
.global _hello
_hello:
MOV R1,R2
IMPORT——导入外部函数。相当于静态引用。不管是否被源文件引用,该标号都会被加入源文件中。
EXTERN——动态引用。如果当前源文件并没实际引用该标号,该标号就不会被加入源文件的符号表中。
GET——相当于引用文件,相当于C语言的#include
GET “hello.s” ;就可以引用hello.s这个文件
RN——给寄存器定义别名;还可以给寄存器组定义别名,参照下面的RLIST。
例:
START
SReg RN R0
MOV SReg,#0x12
主要考虑作用域、变量类型、变量名称。
注意:都存在内存里,而不是寄存器。
作用域
GBL全局 在整个文件起作用,如果EXPORT了就整个项目起作用。
LBL 局部 在宏定义范围内起作用。
类型
A 数字 S字符串 L 逻辑
GBLA/GBLS/GBLL LCLA/LCLS/LCLL
用法——伪指令定义,要缩进
GBLA Var1
SETA/SETS/SETL
用法——写在中间。伪指令操作,不能缩进。
ENTRY
START
GBLA Var1
GBLL Bit2
GBLS Name3
Name3 SETS “norton”
Bit2 SETL {TRUE}
Var1 SETA 0x03 ;立即数不能加标识#。#是常见指令使用的,伪指令不需要。
LDR R0,=Var1 ;常量用 = 号读取 等价于 LDR R0,=0x03
END
RLIST——给寄存器组定义别名
RegList RLIST {R0-R5,R8,R10}
例子:
ENTRY
START
MOV R3,#0x02
RegList RLIST {R0,R1,R2}
LDMIA R3,RegList
END
$变量替换符,类似shell命令
LCLS S1
LCLS S2
S1 SETS “TEST!”
S2 SETS “This is a $S1”
S2结果为This is a TEST!
+ - * / MOD
ROL ROR SHL SHR 移位运算
AND OR NOT EOR 按位逻辑运算
= > < >= <= /=(不等于) <>(不等于)
LAND LOR LNOT LEOR ——L表示Logic
寄存器操作
LDR(大范围寻址)取代MOV
GBLA Age
Age SETA 0x18
LDR R1,=Age ;这样读取的是常量值,而不是对应的地址值(LDR的op只允许Rn和常量,如果是Rn就看作地址,如果是常量,则LDR相当于MOV)
ADR——小范围寻址(相对寻址/+-255)到寄存器,可以查看label的地址
ADR R2,START
ADRL——中范围寻址到寄存器
作用:开辟一片区域,并赋初值
DCB——按字节存储,当前地址赋值为0x01...
TestData DCB 0x01,0x02,0x03
等价于 TestData = 0x01,0x02,0x03
DCW——按半字存储,当前地址赋值为0x01...
DcControl DCW 0x01,0x02,0x03
DCD——按全字存储,每个0x01占4个byte。即保存为0x00000001
如果存放的是字符串,如
DcData DCB “hello”
存放的是6个字节,且是ASC码
SPACE——开辟一个连续区域,并初始化为0
TestData SPACE 100
初始化100个字节为0
MAP——定义结构化内存表首地址的值
MAP/FIELD=>可用^/#代替
MAP 0x100 ;表首地址为0x100
A FIELD 16 ;A长度为16字节,地址为0x100,16字节相当于0x010
B FIELD 32 ;B长度为32字节,地址为0x100+0x010=0x110,32字节相当于0x020
C FIELD 256 ; C长度为256字节,地址为0x110+0x20=0x130
IF ELSE ENDIF 条件
WHILE WEND 循环
MACRO MEND 宏定义
MEXIT 跳出宏
IF ELSE纯伪指令操作实例:
GBLA Age
Age SETA 0x18
IF Age > 0
MOV R0,#0x04
ELSE
MOV R1,#0x04
ENDIF
对比:逻辑值操作
GBLL Bit
Bit SETL {TRUE}
IF Bit = {TRUE}
MOV R0,#0x04
ELSE
MOV R1,#0x04
ENDIF
WHILE纯伪指令操作实例:
WHILE Age < 20
ADD R0,R0,#0x01
Age SETA 0x21
WEND
MACRO实例
格式:[$ label name] macro name $param1,$param2,...
MACRO
$OP hello $param1,$param2
MOV R0,#0x01
MEXIT ;这样就不会执行下面的语句
MOV R1,#0x02
MEND
OP hello AA,BB
上面例子没有使用param1和param2