为了学习android系统而努力。
这个笔记,记录arm汇编语言的伪指令。
伪指令的作用仅在完成汇编过程,一旦汇编结束,伪指令的使命就完成了。
有如下几种伪指令:
指示符 | 功能 |
---|---|
GBLA | 声明和初始化一个全局算术变量,初始值为0 |
GBLL | 声明和初始化一个全局的逻辑变量,初始值为{FALSE} |
GBLS | 声明和初始化一个全局的字符串变量,初始值为空 |
LCLA | 声明和初始化一个局部算术变量,初始值为0,局部算术变量只能在宏中声明 |
LCLL | 声明和初始化一个局部逻辑变量,初始值为{FALSE},局部变量只能在宏中声明 |
LCLS | 声明和初始化一个局部字符串变量,初始字号为空,局部字符串变量只能在宏中进行声明 |
SETA | 给一个局部或全局算术变量赋值 |
SETL | 给一个局部或全局逻辑变量赋值 |
SETS | 给一个局部或全局字符串变量赋值 |
RLIST | 给寄存器集命名 |
CN | 给一个协处理器命名 |
CP | 给一个特定协处理命名,,协处理器号为0-15 |
DN | 给一个双精度VFP寄存器命名 |
SN | 给一个单精度VFP寄存器命名 |
FN | 给一个特定的浮点寄存器命名 |
例子:
MACRO
$label message $a
LCLS err;声明一个局部的字符变量
err SETS "error no: ";给这个字符变量赋值,注意顶格
$label
INFO 0, "err":CC::STR:$a
MEND
GBLA test1
test1 SETA 0xaa;注意顶格
GBLL test2
test2 SETL {TRUE};注意顶格
GBLS test3
test3 SETS "test3";注意顶格
用于为数据分配存储单元,同时也可以完成已分配存储单元的初始化
DCB:用于分配一片连续的字节存储单元并用伪指令中指定的表达式初始化。其中,表达式可以使用双引号的字符串或0-255的数字,DCB可以用“=”代替。内存分配字节数由表达式决定,例子如下:
str DCB "this is test!"
注意,它不像c字符串,arm汇编器不会末尾放入一个’\0’字符。为了构造一个c字符串,可以参考下面写法:
C_string DCB "C_string",0
DCW/DCWU:DCW分配一片连续的半字存储单元,存储空间半字对齐。DCWU跟DCW类似,只是分配的存储单元不严格半字对齐。
DCD/DCDU:分配连续的字存储单元,存储空间字对齐。DCD可以用&符号代替。DCDU跟DCD一样,只不过不严格字对齐。
DCQ/DCQU:DCQ分配连续的8字节存储单元,存储空间字对齐。DCQU跟DCQ一样,只不过不严格字对齐。
DCFD/DCFDU:DCFD用于为双精度浮点数分配一片连续的存储单元。存储空间字对齐,每个双精度浮点数占据两个字单元。DCFDU不严格按照字对齐
DCFS/DCFSU:DCFS为单精度浮点分配连续的存储单元,存储空间字对齐,每个单精度浮点数使用一个字单元。DCFSU不严格按照字对齐
SPACE:分配连续的存储区域并初始化为0,后面跟的是需要分配的字节数。SPACE可以用%代替。例子:
data1 SPACE 255;定义一个255字节的存储区域,存取区域以0值填充
MAP:定义一个结构化的内存表的首地址,可用‘^’代替。格式如下:
MAP 表达式 [,基址寄存器]
当基址寄存器不存在时,表达式的值即为内存表的首地址;
当基址寄存器存在时,内存表的首地址为表达式的值与基址寄存器的和。
FIELD:用于定义一个结构化内存表中的数据,可以用‘#’代替
注意:MAP和FIELD仅用于定义数据结构,不分配实际的存储单元。FIELD指令和MAP指令配合使用用来定义结构化的内存表。MAP指令定义内存表的首地址,FIELD指令定义内存表中的各个数据域,并可以为每个数据域指定一个标号供其他的指令使用
使用如下:
MAP 0x30000000;注意前面的tab
A FIELD 4;定义数据A,长度为4字节
B FIELD 4;定义数据B,长度为4字节
C FIELD 4;定义数据C,长度为4字节
MACRO、MEND:宏定义指令,格式如下:
MACRO
[$标号] 宏名 [$参数1,$参数2。。。]
MEND
MACRO表示一个宏的开始,MEND表示一个宏的结束,MACRO,MEND之间的代码被视为一个整体,称为宏定义体。例子如下:
MACRO
$label moveR1toten
MOV R1,#10
MEND
IF、ELSE、ENDIF:根据逻辑表达式的结果,决定是否编译时加入某个指令序列。格式如下:
IF 逻辑表达式
代码段1
ELSE
代码段2
ENDIF
IF,ELSE,ENDIF分别可以用’[’,’|’,’]'代替
例子如下:
IF test2={TRUE}
MOV R0,#1
ELSE
MOV R0,#0
ENDIF
WHILE、WEND:根据逻辑表达式的结果,决定是否要循环执行这个代码。格式如下:
WHILE 逻辑表达式
代码
WEND
例子如下:
WHILE test1 <= 4
MOV R0,#1
WEND
MEXIT:用于从宏中退出。例子如下:
MACRO
$abc example abc $param1,$param2
; code
WHILE condition1
; code
IF condition2
; code
MEXIT
ELSE
; code
ENDIF
WEND
; code
MEND
ASSERT:格式如下:
ASSERT 逻辑表达式
说明:如果逻辑表达式不满足,则编译器报错
例子如下:
ASSERT label1 <= label2
ALIGN:可以通过填充字节使当前的位置满足一定的对齐方式。格式如下:
ALIGN [表达式[,偏移量]]
其中表达式的值为2的幂,用于指定对齐方式。如果没有指定表达式,则编译器会将当前位置对齐到下一个字的位置。如果存在偏移量,这当前位置的自动对齐到:2的表达式次方+偏移量。
AREA cacheable, CODE, ALIGN=3
rout1 ; code ; aligned on 8-byte boundary
; code
MOV pc,lr ; aligned only on 4-byte boundary
ALIGN 8 ; now aligned on 8-byte boundary
rout2 ; code
AREA:格式如下:
AREA 段名 属性,。。。
说明:AREA用于定义一个代码段、数据段或者特定属性的段。如果段名以数字开头,那么该段名需要用“|”字符括起来,如|7wolf|。
常见属性如下:
例子如下:
AREA Example,CODE,READONLY ; An example code section.
; code
CODE16/CODE32:CODE16指示编译器后面的代码为16位的thumb指令。CODE32指示编译器后面的代码为32位的ARM指令
在使用ARM指令和Thumb指令混合编程的代码里,可用这两条伪指令进行切换。但他们只通知编译器其后指令的类型,并不能对处理器进行状态的切换。
ENTRY:用于指定汇编程序的入口。在一个完整的汇编程序中至少要有一个ENTRY,程序中也可以有多个,此时,程序的真正入口点可在链接时指定,但在一个源文件里最多只能有一个ENTRY或者没有NETRY
例子:
AREA ARMex, CODE, READONLY
ENTRY ; Entry point for the application.
EXPORT ep1 ; Export the symbol so the linker can find it
ep1 ; in the object file.
; code
END
END: 告诉编译器已经到了源程序的结尾
EQU:用于将程序中的数字常量、标号、基于寄存器的值赋予一个等效的名称,这一点类似于C语言的#define。可用“*”代替
格式如下:
名称 EQU 表达式[,类型]
如果表达式为32位的常量,我们可以指定表达式的数据类型,类型域可以有如下三种:CODE16,CODE32,DATA
例如:
NUM EQU 100;
EXPORT:在程序中声明一个全局的标号,该标号可以再其他的文件中引用。用户也可以用GLOBAL代替EXPORT。标号在程序中区分大小写
AREA asm,CODE,READONLY
ENTRY
EXPORT start
start
MOV R0,#10
IMPORT:告诉编译器标号要在当前源文件中使用,但标号是在其他源文件中定义的。不管当前源文件是否使用过该标号,这个标号都会加入到当前源文件的符号表中。标号在程序中区分大小写。
AREA asm,CODE,READONLY
import start
EXTERN:告诉编译器所有使用的符号要在当前源文件中引用,但该标号是在其他源文件中定义的。与IMPORT不同的是,如果当前源文件实际没有引用该标号,该标号就不会被加入到当前文件的符号表中。
RN:用于给一个寄存器定义一个别名。格式如下:
名称 RN 表达式
例如:
Temp RN R0;
GET/INCLUDE:GET将一个源文件包含到当前的源文件中,并将被包含的源文件在当前位置展开进行汇编处理。INCLUDE和GET作用等效。
INCBIN:将一个可执行文件或任意数据文件包含到当前的源文件中,编译时被包含的文件不作任何变动的存放在当前文件中,不进行汇编处理,编译器从后面开始继续处理。
NOP:空操作伪指令
语句格式
[标签] 指令/伪指令/伪操作 操作数 [;语句的注释]
说明:
标签代表地址时,又称为标号,标号分为段内标号和段外标号。段内标号的地址值在汇编时确定,段外编号的地址在链接时确定
在程序段中,标号代表其所在位置与段首地址的偏移量。根据程序计数器和偏移量计算地址即程序相对寻址。
此外在宏定义中也可以使用局部符号。局部符号是0-99的十进制数开始,可以重复定义。
局部标号引用格式:
%{F|B}{A|T} N{routname}
%-表示局部标号引用操作
F-指示编译器只向前搜索
B-指示编译器只向后搜索
A-指示编译器搜索宏的所有嵌套层次
T-指示编译器搜索宏的当前层
N-局部标号,0~99
routname-局部标号作用范围的名称,由ROUT伪指令定义
数字常量3种表示方法:
字符常量:如’a’,‘b’,由单引号括起来
字符串常量:如"name",由双引号括起来
逻辑常量:{TRUE},{FALSE},注意一定要带大括号
S1 SETS "test!"
S2 SETS "this is a $S1";字符串变量S2的值代替为“this is a test!”
这部分笔记已经是几个月之前所写,未做仔细校对,若发现问题,请指出,谢谢。