ARM汇编伪指令.docx
- 文档编号:23340932
- 上传时间:2023-05-16
- 格式:DOCX
- 页数:16
- 大小:22.93KB
ARM汇编伪指令.docx
《ARM汇编伪指令.docx》由会员分享,可在线阅读,更多相关《ARM汇编伪指令.docx(16页珍藏版)》请在冰豆网上搜索。
ARM汇编伪指令
ARM汇编伪指令
在ARM汇编语言源程序中有些特殊助记符,它们没有相对应的操作码或者机器码,通常称为伪指令,它们所完成的操作称为伪操作。
伪指令在源程序中的作用是为完成汇编程序作各种准备工作的,由汇编程序在源程序的汇编期间进行处理,仅在汇编过程中起作用。
在ARM的汇编程序中,有以下几种伪指令:
符号定义伪指令、数据定义伪指令、汇编控制伪指令、宏指令以及其他伪指令。
一、符号定义伪指令
作用:
用于定义ARM汇编程序中的变量、对变量赋值以及定义寄存器的别名等。
符号定义有如下几种伪指令:
用于定义局部变量的LCLA、LCLL和LCLS。
用于定义全局变量的GBLA、GBLL和GBLS。
用于对变量赋值的SETA、SETL和SETS。
为通用寄存器列表定义名称的RLIST。
(1)LCLA、LCLL和LCLS
格式:
LCLA/LCLL/LCLS局部变量名
说明:
LCLA、LCLL和LCLS伪指令用于定义一个汇编程序中的局部变量并初始化。
其中:
LCLA定义一个局部的数字变量,初始化为0。
LCLL定义一个局部的逻辑变量,初始化为F。
LCLS定义一个局部的字符串变量,初始化为空串。
这3条伪指令用于声明局部变量,在其局部作用范围内变量名必须惟一,例如在宏内。
例:
LCLAnum1;定义一个局部数字变量,变量名为num1
LCLLI2;定义一个逻辑变量,变量名为I2
LCLSstr3;定义一个字符串变量,变量名为str3num1SETA0xabcd;将该变量赋值为0xabcd
I2SETL{FALSE};将该变量赋值为真
str3SETS“HELLO”;将该变量赋值为“HELLO”
(2)GBLA、GBLL和GBLS
格式:
GBLA/GBLL/GBLS变量名
说明:
GBLA、GBLL和GBLS伪操作定义一个汇编程序中的全局变量并初始化。
其中:
GBLA定义一个全局数字变量,并初始化为0。
GBLL定义一个全局逻辑变量,并初始化为F。
GBLS定义一个全局字符串变量,并初始化为空串。
这3条伪指令用于定义全局变量,因此在整个程序范围内变量名必须惟一。
(3)SETA、SETL和SETS
格式:
变量名SETA/SETL/SETS表达式
说明:
SETA:
给一个数字变量赋值。
SETL:
给一个逻辑变量赋值。
SETS:
给一个字符串变量赋值。
格式中的变量名必须为已经定义过的全局或局部变量,表达式为将要赋给变量的值。
(4)RLIST
格式:
名称RLIST{寄存器列表}
说明:
RLIST可用于对一个通用寄存器列表定义名称,该名称可在ARM指令LDM/STM中使用。
在LDM/STM指令中,列表中的寄存器为根据寄存器的编号由低到高访问次序,与列表中的寄存器排列次序无关。
例如:
pblockRLIST{R0-R3,R7,R5,R9}
;将寄存器列表名称定义为pblock,可在ARM指令
;LDM/STM中通过该名称访问寄存器列表
二、数据定义伪指令
作用:
为数据分配存储单元,同时初始化。
有如下几种:
DCB字节分配
DCW/DCWU半字(2字节)分配
DCD/DCDU字(4字节)分配
DCQ/DCQU8个字节分配
DCFS/DCFSU单精度浮点数分配
DCFD/DCFDU双精度浮点数分配
SPACE分配一块连续的存储单元
FIELD定义一个结构化的内存表的数据域
MAP定义一个结构化的内存表首地址
(1)DCB
格式:
标号DCB表达式
说明:
分配一块字节单元并用伪指令中指定的表达式进行初始化。
表达式可以为使用双引号的字符串或0~255的数字。
DCB可用“=”代替。
例如:
Array1DCB1,2,3,4,5;数组
str1DCB"Yourarewelcome!
"
;构造字符串并分配空间
(2)DCW/DCWU
格式:
标号DCW/DCWU表达式
说明:
DCW分配一段半字存储单元并用表达式值初始化,它定义的存储空间是半字对齐的。
DCWU功能与DCW类似,只是分配的字存储单元不严格半字对齐。
例如:
Arrayw1DCW0xa,-0xb,0xc,-0xd
;构造固定数组并分配半字存储单元
(3)DCD/DCDU
格式:
标号DCD/DCDU表达式
说明:
DCD伪指令用于分配一块字存储单元并用伪指令中指定的表达式初始化,它定义的存储空间是字对齐的。
DCD也可用“&”代替。
DCDU功能与DCD类似,只是分配的存储单元不严格字对齐。
例如:
Arrayd1DCD1334,234,345435
;构造固定数组并分配字为单元的存储单元
LabelDCDstr1;该字单元存放str1的地址
(4)DCQ/DCQU
格式:
标号DCQ/DCQU表达式
说明:
DCQ用于分配一块以8个字节为单位的存储区域并用伪指令中指定的表达式初始化,它定义的存储空间是字对齐的。
DCQU功能与DCQ类似,只是分配的存储单元不严格字对齐。
例如:
Arrayd1DCQ234234,98765541
;构造固定数组并分配字为单元的存储空间。
;注意:
DCQ不能给字符串分配空间
(5)DCFD/DCFDU
格式:
标号DCFD/DCFDU表达式
说明:
DCFD用于为双精度的浮点数分配一片连续的字存储单元并用伪指令中指定的表达式初始化,它定义的存储空间是字对齐的。
每个双精度的浮点数占据两个字单元。
DCFDU功能与DCFD类似,只是分配的存储单元不严格字对齐。
例如:
Arrayf1DCFD6E2
Arrayf2DCFD1.23,1.45
(6)DCFS/DCFSU
格式:
标号DCFS/DCFSU表达式
说明:
DCFS用于为单精度的浮点数分配一片连续的字存储单元并用表达式初始化,它定义的存储空间是字对齐的。
每个单精度浮点数使用一个字单元。
DCFSU功能与DCFS类似,只是分配的存储单元不严格字对齐。
例如:
Arrayf1DCFS6E2,-9E-2,-.3
Arrayf2DCFSU1.23,6.8E9
(7)SPACE
格式:
标号SPACE表达式
说明:
SPACE用于分配一片连续的存储区域并初始化为0,表达式为要分配的字节数。
SPACE也可用“%”代替。
例如:
freespaceSPACE1000
;分配1000字节的存储空间
(8)MAP
格式:
MAP表达式[,基址寄存器]
说明:
MAP定义一个结构化的内存表的首地址。
此时,内存表的位置计数器{VAR}(汇编器的内置变量)设置成该地址值。
“^”可以用来代替MAP。
表达式可以为程序中的标号或数学表达式,基址寄存器为可选项,当基址寄存器选项不存在时,表达式的值即为内存表的首地址,当该选项存在时,内存表的首地址为表达式的值与基址寄存器的和。
MAP可以与FIELD伪操作配合使用来定义结构化的内存表。
例如:
MAP0x130,R2;内存表首地址为0x130+R2
(9)FIELD
格式:
标号FIELD字节数
说明:
FIELD用于定义一个结构化内存表中的数据域。
“#”可用来代替FIELD。
FIELD常与MAP配合使用来定义结构化的内存表:
FIELD伪指令定义内存表中的各个数据域,MAP则定义内存表的首地址,并为每个数据域指定一个标号以供其他的指令引用。
需要注意的是MAP和FIELD伪指令仅用于定义数据结构,并不分配存储单元。
例如:
MAP0xF10000;定义结构化内存表首地址为0xF10000
countFIELD4;定义count的长度为4字节,位置0xF1000+0xFIELD4;定义x的长度为4字节,位置为0xF1004
yFIELD4;定义y的长度为4字节,位置为0xF1008
三、汇编控制伪指令
作用:
指引汇编程序的执行流程。
常用的伪操作包括:
MACRO和MEND:
宏定义的开始与结束。
IF、ELSE和ENDIF:
根据逻辑表达式的成立与否决定是否在编译时加入某个指令序列。
WHILE和WEND:
根据逻辑表达式的成立与否决定是否循环执行这个代码段。
MEXIT:
从宏中退出。
(1)MACRO和MEND
格式
MACRO
[$标号]宏名[$参数1,$参数2,……]
指令序列
MEND
其中,$标号在宏指令被展开时,标号可被替换成相应的符号(在一个符号前使用$,表示程序在汇编时将使用相应的值来替代$后的符号),$参数1为宏指令的参数,当宏指令被展开时将被替换成相应的值,类似于函数中的形式参数。
(2)IF、ELSE和ENDIF
格式:
IF逻辑表达式
代码段1
ELSE
代码段2
ENDIF
说明:
能根据逻辑表达式的成立与否决定是否在编译时加入某个指令序列。
IF、ELSE和ENDIF分别可以用“[”,“|”,“]”代替。
如果IF后面的逻辑表达式为真,则编译代码段1,否则编译代码段2。
ELSE及代码段2也可以没有,这时,当IF后面的逻辑表达式为真时,则代码段1,否则继续编译后面的指令。
(3)WHILE和WEND
格式:
WHILE逻辑表达式
代码段
WEND
说明:
WHILE和WEND伪指令能根据逻辑表达式的成立与否决定是否循环执行这个代码段。
当WHILE后面的逻辑表达式为真时,则执行代码段,该代码段执行完毕后,再判断逻辑表达式的值,若为真则继续执行,一直到逻辑表达式的值为假。
例如:
GBLAnum;声明全局的数字变量num
numSETA9;由num控制循环次数
…
WHILEnum>0
subr0,r0,1
addr1,r1,1
WEND
四、宏定义伪指令
在程序中调用该宏
examjumpsub,det;调用宏jump,宏的标号为exam,参数1为sub,参数2为det
程序被汇编后,宏的展开结果:
…
examloop1
…
BGEexamloop1
examloop2
BLsub
BGTexamloop2
ADRdet
宏指令可以重复使用,与子程序有些类似,子程序可以节省存储空间,提供模块化的程序设计。
但是使用子程序结构时需要保存/恢复现场,从而增加了系统的开销。
使用说明:
在子程序比较短而需要传递的参数比较多的情况下,可使用宏汇编技术。
例子
MACRO;宏定义开始
$labeljump$a1,$a2;宏的名称为jump,有2个参数a1和a2
$label.loop1;$label.loop1为宏体的内部标号
…
BGE$label.loop1
$label.loop2
BL$a1;参数$a1为一个子程序的名称
BGT$label.loop2
…
ADR$a2
…
MEND;宏定义结束
五、其他伪指令
在汇编程序中经常会使用一些其他的伪指令,包括以下18条:
ASSERTAREA
ALIGNCODE16/CODE32
ENTRYEND
EQUIMPORT
EXPORT/GLOBALEXTERN
INCBINGET/INCLUDE
RNROUT
ADRADRL
LDRNOP
(1)ASSERT
格式:
ASSERT逻辑表达式
说明:
ASSERT用来表示程序的编译必须满足一定的条件,如果逻辑表达式不满足,则编译器会报错,并终止汇编。
例如:
ASSERTver>7;保证ver>7
2)AREA
格式:
AREA段名属性,……
说明:
AREA用于定义一个代码段、数据段或者特定属性的段。
如果段名以数字开头,那么该段名需用“|”字符括起来,如|7wolf|,用C的编译器产生的代码一般也用“|”括起来。
属性部分表示该代码段/数据段的相关属性,多个属性可以用“,”分隔。
常见属性如下:
①DATA:
定义数据段,默认属性是READWRITE。
②CODE:
定义代码段,默认属性是READONLY。
③READONLY:
表示本段为只读。
④READWRITE:
表示本段可读写。
⑤ALIGN=表达式,表示段的对齐方式为2的表达式次方,例如:
表达式=3,则对齐方式为8字节对齐。
表达式的取值范围为0~31。
⑥COMMON属性:
定义一个通用段,这个段不包含用户代码和数据。
(3)ALIGN
格式:
ALIGN[表达式[,偏移量]]
说明:
ALIGN伪操作可以通过填充字节使当前的位置满足一定的对齐方式。
表达式的值为2的幂,如1、2、4、8、16等,用于指定对齐方式。
如果伪操作中没有指定表达式,则编译器会将当前位置对齐到下一个字的位置。
偏移量也是个数字表达式,如果存在偏移量,则当前位置自动对齐到2的表达式值次方+偏移量。
例如:
AREA||.data||,DATA,READWRITE,ALIGN=2
(4)CODE16/CODE32
格式:
CODE16/CODE32
说明:
CODE16伪操作指示编译器后面的代码为16位的Thumb指令。
CODE32伪操作指示编译器后面的代码为32位的ARM指令。
如果在汇编源代码中同时包含Thumb和ARM指令时,可以用“CODE32”通知编译器后的指令序列为32位的ARM指令,用“CODE16”伪指令通知编译器后的指令序列为16位的Thumb指令。
CODE16/CODE32不能对处理器进行状态的切换。
例如:
CODE32;32位的ARM指令
AREA||.text||,CODE,READONLY
…
LDRR0,=0x8500;
BXR0;程序跳转,并将处理器切换到Thumb状态
…
CODE16;16位的Thumb指令
ADDR3,R3,1
END;源文件结束
(5)ENTRY
格式:
ENTRY
说明:
ENTRY用于指定汇编程序的入口。
在一个完整的汇编程序中至少要有一个ENTRY,程序中也可以有多个,此时,程序的真正入口点可在链接时指定,但在一个源文件里最多只能有一个ENTRY或者没有ENTRY。
(6)END
格式:
END
说明:
END告诉编译器已经到了源程序的结尾。
例如:
AREAconstdata,DATA,READONLY
…
END;结尾
(7)EQU
格式:
名称EQU表达式[,类型]
说明:
EQU用于将程序中的数字常量、标号、基于寄存器的值赋予一个等效的名称,这一点类似于C语言中的#define.
可用“*”代替EQU。
如果表达式为32位的常量,我们可以指定表达式的数据类型,类型域可以有以下3种:
CODE16/CODE32/DATA
例如:
num1EQU1234;定义num1为1234
addr5EQUstr1+0x50
d1EQU0x2400,CODE32;定义d1的为0x2400,且该处为32位的ARM指令
(8)EXPORT/GLOBAL
格式:
EXPORT/GLOBAL标号[,WEAK]
说明:
EXPORT在程序中声明一个全局标号,其他文件中的代码可以被该标号引用。
用户也可以用GLOBAL代替EXPORT。
[,WEAK]可选项声明其他文件有同名的标号,则该同名标号优先于该标号被引用。
例如:
AREA||.text||,CODE,READONLY
mainPROC
…
ENDP
EXPORTmain;声明一个可全局引用的函数main
…
END
(9)IMPORT
格式:
IMPORT标号[,WEAK]
说明:
告诉编译器,这个标号要在当前源文件中使用,但标号是在其他的源文件中定义的。
[,WEAK]:
如果所有的源文件都没有找到这个标号的定义,编译器也不会提示错误信息,同时编译器也不会到当前没有被INCLUDE进来的库中去查找该符号。
使用IMPORT为操作声明一个符号是在其他源文件中定义的。
如果链接器在链接处理时不能解析该符号,而且IMPORT为操作中没有指定[WEAK]选项,则链接器将会报告错误。
如果链接器在链接处理时不能解析该符号,而IMPORT伪操作中指定了[WEAK]选项,则链接器不会报告错误,而是进行下面的操作:
如果该符号被B或BL指令引用,则该符号被设置成下一条指令的地址,该B或者BL指令相当于一条NOP指令。
例如“Bsign”,“sign”不能被解析,则该指令被忽略为NOP指令,继续执行下面的指令,也就是将sign理解为下一条指令的地址。
其他情况下该符号被设置为0。
例如:
AREAmycode,CODE,READONLY
IMPORT_printf
;通知编译器当前文件要引用函数_printf
…
END
(10)EXTERN
格式:
EXTERN标号[,WEAK]
说明:
告诉编译器,标号要在当前源文件中引用,但是该标号是在其他的源文件中定义的。
与IMPORT不同的是,如果当前源文件实际上没有引用该标号,该标号就不会被加入到当前文件的符号表中。
使用方法:
使用IMPORT为操作声明一个符号是在其他源文件中定义的。
如果链接器在链接处理时不能解析该符号,而且IMPORT为操作中没有指定[WEAK]选项,则链接器将会报告错误。
如果链接器在链接处理时不能解析该符号,而IMPORT伪操作中指定了[WEAK]选项,则链接器不会报告错误,而是进行下面的操作:
如果该符号被B或BL指令引用,则该符号被设置成下一条指令的地址,该B或者BL指令相当于一条NOP指令。
例如“Bsign”,“sign”不能被解析,则该指令被忽略为NOP指令,继续执行下面的指令,也就是将sign理解为下一条指令的地址。
其他情况下该符号被设置为0。
[,WEAK]:
即使所有的源文件都没有找到这个标号的定义,编译器也不给出错误信息。
例如:
AREA||.text||,CODE,READONLY
…
EXTERN_printf,WEAK;告诉编译器当前文件要引用标号,如果找不到,则不提示错误
…
END
(11)GET/INCLUDE
格式:
GET文件名
说明:
GET将一个源文件包含到当前的源文件中,并将被包含的源文件在当前位置展开进行汇编处理。
INCLUDE和GET的作用是等效的。
使用方法:
在某源文件中定义一些宏指令,用MAP和FIELD定义结构化的数据类型,用EQU定义常量的符号名称,然后用GET/INCLUDE将这个源文件包含到其他的源文件中。
使用方法与C语言中的“#include”相似。
GET/INCLUDE只能用于包含源文件,包含其他文件则需要使用INCBIN伪指令。
例如:
AREAmycode,DATA,READONLY
GETE:
\code\prog1.s;通知编译器在当前源文件包含源文件E:
\code\prog1.s
GETprog2.s;通知编译器当前源文件包含可搜索目录下的prog2.s
…
END
(12)INCBIN
格式:
INCBIN文件名
说明:
INCBIN将一个数据文件或者目标文件包含到当前的源文件中,编译时被包含的文件不作任何变动地存放在当前文件中,编译器从后面开始继续处理。
例如:
AREAconstdata,DATA,READONLY
INCBINdata1.dat;源文件包含文件data1.dat
INCBINE:
\DATA\data2.bin
;源文件包含文件E:
\DATA\data2.bin
…
END
(13)RN
格式:
名称RN表达式
说明:
RN用于给一个寄存器定义一个别名,以便程序员记忆该寄存器的功能。
名称为给寄存器定义的别名,表达式为寄存器的编码。
例如:
countRNR1;给R1定义一个别名count
(14)ROUT
格式:
[名称]ROUT
说明:
ROUT可以给一个局部变量定义作用范围。
在程序中未使用该伪指令时,局部变量的作用范围为所在的AREA,而使用ROUT后,局部变量的作用范围为当前ROUT和下一个ROUT之间。
例如:
routineROUT;定义局部标号的有效范围
…
1routine;routine内的局部标号1
…
BEQ%1routine;若条件成立,则跳转到routine范围内的局部标号1
…
OtherroutineROUT;定义新的局部标号的有效范围
(15)LTORG
说明:
LTORG用于声明一个数据缓冲池(literalpool)的开始。
通常放在无条件跳转指令之后,或者子程序返回指令之后,以免处理器错误地将数据缓冲池中地数据作为指令来执行。
例如:
Func1
……
MOVPC,LR
LTORG
DATASPACE26;从data标号开始预留256字节地内存单元
END
(16)ADR小范围地址读取
格式:
ADR{
说明:
将基于PC相对偏移的地址值或基于寄存器相对偏移的地址值(expr地址表达式)读取到目标寄存器Rd中。
当地址值是非字对齐时,取值范围在-255~255字节之间;
当地址值是字对齐时,取值范围在-1020~1020字节之间。
在汇编编译源程序时,ADR伪指令被编译器替换成一条合适的指令。
通常,编译器用一条ADD指令或SUB指令来实现该ADR伪指令的功能。
若不能用一条指令实现,则产生错误,编译失败。
对于基于PC相对偏移的地址值时,给定范围是相对当前指令地址后两个字处(因为ARM7TDMI为三级流水线)。
可以用ADR加载地址实现查表。
例如:
LOOPMOVR1,#0xF0
ADRR2,LOOP;将LOOP的地址放入R2,因为PC值为当前指令地址值加8字节,所以本ADR伪指令将被编译器换成“SUBR2,PC,0XC”
(17)ADRL中等范围地址读取
格式:
ADRL{
说明:
类似于ADR,但比ADR读取更大范围的地址。
当地址值是非字对齐时,取值范围在-64KB~64KB之间;
地址值是字对齐时,取值范围在-256KB~256KB之间。
在汇编编译源程序时,A
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- ARM 汇编 指令