ARM汇编伪指令详解

时间:2021-11-17 08:05:07
转自:http://hi.baidu.com/boyshen/blog/item/1e26c965ce1b93fbf6365449.html
ARM汇编程序分析过程中,比较难理解的是他的伪操作、宏指令和伪指令。在读vivi时遇到很多不懂的,所以在此对引导程序中出现伪操作、宏指令和伪指令进行总结, *****************************************************
  GEToption.s // GET和INCLUDE功能相同功能:引进一个被编译过的文件。格式: GET filename 其中:fiename 汇编时引入的文件名,可以有路径名。 GET符号在汇编时对宏定义,EQU符号以及存储映射时是很有用的,在引入文件汇编完以后,汇编将从GET符号后开始。在被引入的文件中可能有GET符号再引入其他的文件。GET符号不能用来引入目标文件。 *****************************************************
、INTPND EQU 0x01e00004 //EQU可以用“ *”代替,在阅读源程序时注意。功能:对一个数字常量赋予一个符号名。格式:name EQU expression 其中:name 符号名。Expression 寄存器相关或者程序相关的固定值。 使用EQU定义常量,与C语言中用#define定义一个常量相同。
例:num EQU 2 ; 数字2赋予符号num *****************************************************
  GBLL THUMBCODE
 [ {CONFIG} = 16
 THUMBCODE SETL {TRUE}
 CODE32
 |
THUMBCODE SETL {FALSE} ]
 [ THUMBCODE CODE32 ;for start-up code for Thumb mode ] //其中[=IF ,|=ELSE ,]= ENDIF, CODE32 表明一下操作都在ARM状态。这些都是伪操作这段理解为设定THUMCODE的值,然后确定,用户的程序是在ARM状态还是THUM状态。 *****************************************************
MACRO
$HandlerLabel HANDLER $HandleLabel
$HandlerLabel
 sub sp,sp,#4 ;decrement sp(to store jump address)
 stmfd sp!,{r0} ;PUSH the work register to stack
 ldr r0,=$HandleLabel;load the address of HandleXXX to r0
 ldr r0,[r0] ;load the contents(service routine start address) of HandleXXX
 str r0,[sp,#4] ;store the contents(ISR) of HandleXXX to stack
 ldmfd sp!,{r0,pc} ;POP the work register and pc(jump to ISR)
MEND //MACRO……MEND 功能:标志一下宏的定义。
格式:MACRO Macro_prototype MEND
宏表达式的格式如下: {$label} macroname {$ parameter{,parameter2}…}
其中: $ label 参数,在宏使用时,被给定的符号替代。 Macroname 宏的名称,并不一定以一条指令或者符号名开始。 $parameter 在宏使用时,被替代的参数,格式为:$parameter=“default value” 在宏体中,参数如:$parameter和变量一样使用,在被宏引用时,被赋于新值,参数必须用“$”符号加于区别。$label在宏定义内部符号 时很有用,可以看作宏的参数。使用“|”符号作为使用一个参数缺省值的变量,如果使用的是一个空格符串,将省去该变量。在使用内部标志的宏定义中,将内部 标志定义为带后缀的标志,将会很有用。如果在扩展中空间不够,可以作为参数和后继文字之间或者参数之间使用圆点隔开,但在文本和后继参数之间不能使用圆点。宏可以定义局部变量的范围。
宏还可以嵌套使用。例: MACRO $label xmac $p1,$p2 LCLS err $labell,loopl BGE $pl $labell,loop2 BL $p1 BEG $p1 BEG $labell,loop2 MEND *****************************************************
$和$$ //$临时变量替换,若程序中需要用字符$则用$$来表示,通常情况下,包含在两个||之间的$并不表示进行变量替换,但是如果|线是在双引号内,则将进行变量替换。用“.”来分割出变量名的用法, GBLS STR1 GBLS STR2 STR1 SETS "AAA" STR2 SETS "BBB$$STR1.CCC" //汇编后STR2的值为bbAAACCC *****************************************************
IMPORT Main ; The main entry of mon program //该伪操作告诉编译器当前的符号不是在本文件中定义的,在本源文件中可能引用该符号,而不论该源文件是否使用该符号,该符号都将被加入到本源文件中。
格式: IMPORT symbol {[WEAK]} symbol 引用的符号的名称,他是区分大小写的,[WEAK]指定这个选项后,如果symbol所在的源文件中没有被定义,编译器也不会报错。他和EXTERN作用相同,不同之处在于,如果本源文件没有实际引用该符号,该符号将不会被加入到本源文件的符号表中。 *****************************************************
AREA Init,CODE,READONLY ENTRY //功能:指示汇编器汇编一段新的代码或新的数据区。
格式: name 给出的特定段名。以数字开头,必须加竖线,否则,将报错,例如:|1_Data-Area|。某些名字已保留,如:|C$$code|已经被C编译器用作代码,或者用作与C库相连的代码段。 Attr 段名属性,下列属性是有效的: ALIGN=expression 缺省状态下,AOF段将按4个字节对准,expression可以是2~31之间的整数,该段将按2(上标为expression)字节对准。例如,espression等于 10,该段将按1KB对准。 CODE 特定机器指令,缺省为READONLY。 COMDEF 通用段定义。该AOF段可能包括代码和数据,但必须与其他段名相区别。 COMMON 通用数据段,无须再注释定义任何代码和数据,通常由链接器初始化为零。 DATA 包含数据,但是不包含指令,缺省为READWRITE INTERWORK 表明代码段可以适用ARM/Thumb interworking功能。 NOINIT 表明数据段可以初始化为零,只包含指示符。 PIC 表明定位独立段,可以不修改情况下,在任意地址执行。 READONLY 表明该段可读可写。汇编时,必须至少有一个AREA指示符。使用AREA符号可以将源程序区分,但是必须不重名。通常需要独立的AOF段做为代码或者数据段,较大程序 可以分为多个代码段。AOF段可以定义局部标签的范围,可以使用ROUT符号。如果没有任何的AREA指示符定义,汇编器将会产生名为|$$$$$$$| 的AOF段和一条诊断信息,将限制由于缺少指示符而产生的错误信息,但是并不一定会成功汇编。 *****************************************************
LTORG //LTORG是在此指令出现的地方放一个文本池(literal pool). 在ARM汇编中常用到 ldr r0, =instruction 将地址instruction载入r0 此时编译器将ldr尽可能的转变成mov或mvn指令。 如果转变不成, 将产生一个ldr指令,通过pc相对地址从一块保存常数的内存区读出instruction的值。此内存区既是文本池。一般的, 文本池放在END指令之后的地方。但是, 如果偏移地址大于4k空间, ldr指令会出错(因为ldr的相对偏移地址为12-bit的值). 此时使用LTORG放到会出错的ldr指令附近,以解决此问题。编译器会收集没有分配的ldr的值放到此文本池中。所以必须在LDR指令前后4KB的范围内用LTORG显式地在代码段中添加一个文字池。 *****************************************************
LDR r0,=WTCON ;watch dog disable LDR r1,=0x0 功能:将一个32位常量或地址读取至寄存器。格式: LDR{condition} register,=[expression|Label-expression] 其中: condition 可选的条件代码。 register 读取的寄存器。 expression 数字常量: 如果该数字常量在MOV或MVN指令的范围中,汇编器会产生合适的指令; 如果该数字量不在MOV或MVN指令的范围中,汇编器把该常量于程序后,用程序相关的LDR伪指令读取,PC与该常量的偏移量不得超过4KB。 Label-expression 程序相关的或外部的表达式。汇编器将其存放在程序后的常量库(称为文字池(literal pool))中,用程序相关的LDR伪指令读取,PC与与该常量的偏移量不得超过4KB。 LDR伪指令的使用有两个目的: 对于不能被MOV和MVN指令所读取的立即数,将其变成常量,进行读取。 将一个程序相关的或外部的表达式读取进寄存器中。例: LDR R1, =0xfff LDR R2, =place *****************************************************
DCD 0x11110090 ;Bank0=OM[1:0], Bank1~Bank7=16bit, bank2=8bit; //DCD或“&” 功能: 分配一个或多个字,从4个字节边界开始。格式: {label}DCD expression{,expression}… 其中: expression 可以是:一个数学表达式;一个程序相关的表达式。 如果在Thumb代码中,使用DCD符号定义带标志的数据时则必须使用DATA符号。 按4个字节对准时,DCD符号会在第一个字节之前插入3个字节的空字符,如果无须对准的话,可以使用DCDU符号。例: datal DCD 1,5,20 data2 DCD mem06 data3 DCD glb+4 *****************************************************
 十一ALIGN //功能:从1个字边界开始。
格式: ALIGN {expression {,offset-expression} } 其中: expression 2(上标为0)到2(上标为31)之间的任意数幂,当前按2(上标为n)字节对准,如果该参数没有指定,ALIGN将按字对准。 Offset-expression 定义expression指定的对准方式的字节偏移量。使用ALIGN符号,保证程序正确对准。对于Thumb地址,使用ALIGN符号保证其按字对准,例如:ADR Thuub伪指令只能读取字对准的地址。 在代码段出现数据定义符时,使用ALIGE符号。当在代码段使用数据定义符(DCB,DCW,DCWU,DCDU和%),程序计数器PC并不一定按字对准。汇编器会在下一条指令时插入3个字节,保证: ARM状态下按字对准; Thumb状态下按半字对准。 在Thumb状态下,可以使用ALIGN2对Thumb代码按半字对准。 使用ALIGN状态下,还可以充分利用一些ARM处理器的Cache,例如,ARM940T有一个每行4字的Cache,使用ALIGN16按16字节对准,从而最大限度使用Cache。 *****************************************************
十二 、^ _ISR_STARTADDRESS //MAP与"^" MAP用于定义一个结构化的内存表(StorageMAP)的首地址。此时,内存表的位置计数器{VAR}(汇编器的内置变量)设置成该地址值。MAP可以用”^”代替。
语法:MAP expr {,base-register} 其中,expr为数字表达式或者是程序中已经定义过的标号。Base-register为一个寄存器。当指令中没有Base-register时, expr为结构化内存表的首地址。此时,内存表的位置计数器{VAR}设置成该地址值。当指令中包含这一项时,结构化内存表的首地址为expr和Base -register寄存器内容的和。使用说明:MAP伪操作和FIELD伪操作配合使用来定义结构化的内存表结构。
 举例:MAP伪操作 MAP fun ;fun就是内存表的首地址 MAP 0x100,R9 ;内存表的首地址为 R9+0x100 *****************************************************
十三、HandleReset # 4
           HandleUndef # 4
           HandleSWI   # 4 //FIELD和"#" FIELD 用于定义一个结构化的内存表中的数据域。
FIELD 可用“#”代替。语法:{label} FIELD expr 其中:{label}为可选的。当指令中包含这一项时,label的值为当前内存表的位置计数器{VAR}的值。汇编编译器处理了这条FIELD伪操作后。内存表计数器的值将加上expr.expr表示本数据域在内存中所占的字节数。
使用说明:MAP伪操作和FIELD伪操作配合使用来定义结构化的内存表结构。 MAP伪操作定义内存表的首地址。FIELD伪操作定义内存表的数据域的字节长度,并可以为每一格数据域指定一个标号,其他指令可以引用该标号。 MAP伪操作中的Base-registe寄存器值队以其后所有FIELD伪操作定义的数据域是默认使用的,直到遇到新的包含Base-registe项的MAP伪操作需要特别注意的是, MAP伪操作和FIELD伪操作仅仅是定义数据结构,他们并不实际分配内存单元。
由MAP伪操作和FIELD伪操作配合 定义的内存表有3种:基于绝对地址的内存表,基于相对地址的内存表和基于PC的内存表。
举例:基于绝对地址的内存表用伪操作序列定义一个内存表,其首地址为固定的地址8192(0X2000),该内存表中包括5个数据域。 Consta长度为4个字节;constb长为4个字节,x长为8字节;y长为8字节;string长为16字节。这种内存表成为基于绝对地址的内存表。 MAP 8192 ; //内存表的首地址8192(0x2000) Consta FIELD 4 ; //consta 长为4字节,相对位置为0 Constb FIELD 4; //constb长为4字节,相对位置为4 X FIELD 8; // X长为8字节,相对位置为8 Y FIELD 8; // y长为8字节,相对位置为16 String FIELD 16 ;// String为16字节,相对位置为24 在指令中,可以这样引用内存表中的数据域; LDR R0,consta; //将consta地址处对应内存加载到R0上面的指令仅仅可以访问LDR指令前后4KB地址范围的数据域。举例:相对绝对地址的内存表下面的伪操作序列定义一个内存表,其首地址为0与R9寄存器值得和,该内存表中包含5个数据域。这种表称为相对地址的内存表。 MAP 0,R9;//内存表的首地址寄存器R9的值 Consta FIELD 4 ; //consta 长为4字节,相对位置为0 Constb FIELD 4; //constb长为4字节,相对位置为4 X FIELD 8; // X长为8字节,相对位置为8 Y FIELD 8; // y长为8字节,相对位置为16 String FIELD 16;// String为16字节,相对位置为24 可以通过下面的指令访问地址范围超过4KB的数据; ADR R9, Field ; //伪指令 LDR R5,Constb;//相当于LDR R5,[R9,#4] 在这里,内存表中的数据都是相对于R9寄存器的内容,而不是相对于一个固定的地址。通过在LDR中指定不同的基址寄存器的值,定义的内存表结构可以在程序中有多个实例。可多次使用LDR指令,用以实现不同的程序实例。举例:基于PC的内存表 Data SPACE 100 ; //分配100字节的内存单元,并初始化为0 MAP Data;//内存表的首地址为Datastruc内存单元 Consta FIELD 4 ; //consta 长为4字节,相对位置为0 Constb FIELD 4; //constb长为4字节,相对位置为4 X FIELD 8; // X长为8字节,相对位置为8 Y FIELD 8; // y长为8字节,相对位置为16 String FIELD 16;// String为16字节,相对位置为24 可以通过下面的指令访问范围不超过4kb的数据; LDR R5,constb ;相当于 LDR R5,[PC,offset]*****************************************************
***********************************************************************************************************************************************************
补充:
MAP与FIELD只是定义结构化内存表,并不实际分配内存空间。那他们的作用是什么呢?昨天百度了一下,碰到一个问同样问题的,可惜的是这种细节问题都没人来回答。今天翻阅了一下《ARM体系结构与编程》,发现答案其实早就有了。
举例:           Datastruc          SPACE           280             ;分配280个字节单元
                      MAP                  Datastruc                           ;内存表的首地址为 Datastruc内存块
                      consta               FIELD             4                 ;长度4字节,相对地址0
                      constab             FIELD             4                  ;长度4字节,相对地址4
                         x                     FIELD             8                  ;长度8字节,相对地址8
                         y                    FIELD              8                  ;长度8字节,相对地址16
                     string                FIELD             256                ;长度256字节,相对地址24
很明显MAP与FIELD是配合其它分配内存单元的指令使用的。在这里推荐一下《ARM体系结构与编程》,要搞懂汇编指令细节的朋友可以看下,我自己也在研究。                   --------------------------------          by   sunjy516          2011.6.8
************************************************************************************************************************************************************
十四 RN 在局部标号中: %表示引用操作 F指示编译器只向前搜索。 B指示编译器只向后搜索。 A指示编译器搜索宏的所有嵌套层。 T指示编译器搜索宏的当前层次。若F、B没有指定则先向前搜索,再向后搜索。若A、T都没有指定则先从当前层到最高层,比当前层低的不再搜索