分类: LINUX

2009-10-21 16:39:09

ARM 汇编程序的由机器指令,伪指令和宏指令组成。伪指令不像机器指令那样在处理器运行期间由机器执行,而是汇编程序对源程序汇编期间由汇编程序处理。在前面的指令集章节中,我们已经接触了几条常用到的伪指令,如ADR 、ADRL、LDR、NOP 等,把它们和指令集一起介绍是因为它们在汇编时会被合适的机器指令代替,实现真正机器指令操作。宏是一段独立的程序代码,它是通过伪指令定义的,在程序中使用宏指令即可调用宏。

当程序被汇编时,汇编程序将对每个调用进行展开,用宏定义取代源程序中的宏指令。

A.4.1  符号定义伪指令

符号定义伪指令用于定义ARM 汇编程序的变量,对变量进行赋值以及定义寄存器名称,该类伪指令如下:

全局变量声明:GBLA、GBLL 和GBLS。

局部变量声明:LCLA、LCLL 和LCLS。

变量赋值: SETA、SETL 和SETS。

为一个通用寄存器列表定义名称:RLIST。

为一个协处理器的寄存器定义名称:CN。

为一个协处理定义名称: CP。

为一个VFP 寄存器定义名称:DN 和SN。

为一个FPA 浮点寄存器定义名称:FN。

GBLA、GBLL、GBLS

全局变量声明伪指令。

GBLA 伪指令用于声明一个全局的算术变量,并将其初始化为0。

GBLL 伪指令用于声明一个全局的逻辑变量,并将其初始化为{FALSE}。

GBLS 伪指令用于声明一个全局的字符串变量,并将其初始化为空字符串“”。

伪指令格式:

GBLA variable

GBLL variable

GBLS variable

其中:variable 定义的全局变量名,在其作用范围内必须惟一。全局变量的作用范围为包含该变量的源程序。

伪指令应用举例如下:

GBLL codedbg ;声明一个全局逻辑变量

codebg SETL {TRUE} ;设置变量为{TRUE}

LCLA、LCLL、LCLS

局部变量声明伪指令,用于宏定义的体中。

LCLA 伪指令用于声明一个局部的算术变量,并将其初始化为0。

LCLL 伪指令用于声明一个局部的逻辑变量,并将其初始化为{FALSE}。

LCLS 伪指令用于声明一个局部的字符串变量,并将其初始化为空字符串“”。

伪指令格式:

LCLA variable

LCLL variable

LCLS variable

其中:variable 定义的局部变量名。在其作用范围内必须惟一。局部变量的作用范围为包含该局部变量只能在宏中进行声明及使用。

伪指令应用举例如下:

MACRO ;声明一个宏

SENDDAT $dat ;宏的原型

LCLA bitno ;声明一个局部算术变量

bitno SETA 8 ;设置变量值为8

MEND

SETA、SETL、SETS

变量赋值伪指令。用于对已定义的全局变量,局部变量赋值。

SETA 伪指令用于给一个全局/局部的算术变量赋值。

SETL 伪指令用于给一个全局/局部的逻辑变量赋值。

SETS 伪指令用于给一个全局/局部的字符串变量赋值。

伪指令格式:

variable_a SETA expr_a

variable_l SETL expr_l

variable_s SETS expr_s

其中:variable_a 算术变量。用GBLA、LCLA 伪指令定义的变量。

expr_a 赋值的常数。

variable_l 逻辑变量。用GBLL、LCLL 伪指令定义的变量。

expr_l 逻辑值,即{TRUE}或{FALSE}。

variable_s 字符串变量。用GBLS、LCLS 伪指令定义的变量。

expr_s 赋值的字符串。

伪指令应用举例如下:

GBLS ErrStr

ErrStr SETS “No,semaphone”

RLIST

RLIST 为一个通用寄存器列表定义名称。伪指令格式如下:

name RLIST {reglist}

其中:name 要定义的寄存器列表的名称。

reglist 通用寄存器列表。

伪指令应用举例如下:

LoReg RLIST {R0-R7} ;定义寄存器列表LoReg

STMFD SP!,LoReg ;保存寄存器列表LoReg

CN

CN 为一个协处理器的寄存器定义名称。

伪指令格式:

name CN expr

其中:name 要定义的协处理器的寄存器名称。

expr 协处理器的寄存器编号,数值范围为0~15。

伪指令应用举例如下:

MemSet CN l ;将协处理的寄存器l 名称定义为MemSet

CP

CP 为一个协处理器定义的名称。

伪指令格式:

name CP expr

其中:name 要定义的协处理器名称。

expr 协处理器的编号,数值范围为0~15。

伪指令应用举例如下:

DivRun CN 5 ;将协处理器5 名称定义为DivRun

DN、SN

DN 和SN 为VFP 的寄存器的名称定义的伪指令。

DN 为一个双精度原VFP 寄存器定义名称。

SN 为一个单精度的VFP 寄存器定义名称。

伪指令格式:

name DN expr

name SN expr

其中:name 要定义的VFP 寄存器名称。

expr 双精度的VFP 寄存器编号为0~15,单精度的VFP 寄存器编号为0~31。

伪指令应用举例如下:

cdn DN 1 ;将VFP 双精度寄存器1 名称定义为cdn

rex SN 3 ;将VFP 单精度寄存器3 名称定义为rex

FN

FN 为一个FPA 浮点寄存器定义名称

伪指令格式:

name FN expr

其中:name 要定义的浮点寄存器名称。

expr 浮点寄存器的编号,值为0~7。

伪指令应用举例如下:

ibq FN l ;将浮点寄存器l 名称定义为ibq

A.4.2  数据定义伪指令

数据定义伪指令用于数据表定义,文字池定义,数据空间分配等。该类伪指令如下:

声明一个文字池:LTORG。

定义一个结构化的内存表的首地址:MAP。

定义结构化内存表中的一个数据域:FIELD。

分配一块内存空间,并用0 初始化:SPACE。

分配一段字节的内存单元,并用指定的数据初始化:DCB。

分配一段字的内存单元,并用指令的数据初始化:DCD 和DCDU。

分配一段字的内存单元,将每个单元的内容初始化为该单元相对于静态基址寄存器的偏移量:DCDO。

分配一段双字的内存单元,并用双精度的浮点数据初始化:DCFD 和DCFDU。

分配一段字的内存单元,并用单精度的浮点数据初始化:DCFS 和DCFSU。

分配一段字的内存单元,并用单精度的浮点数据初始化,指定内存单元存放的是代码,而不是数据:DCI。

分配一段双字的内存单元,并用64 位整数数据初始化:DCQ 和DCQU。

分配一段半字的内存单元,并用指定的数据初始化:DCW 和DCWU。

LTORG

LTORG 用于声明一个文字池,在使用LDR 伪指令时,要在适当的地址加入LTORG 声明文字池,这样就会把要加载的数据保存在文字池内,再用ARM 的加载指令读出数据。(若没有使用LTORG 声明文字池,则汇编器会在程序末尾自动声明。)

伪指令格式:

LTORG

伪指令应用举例如下:

LDR R0,=0x12345678

ADD R1,R1,R0

MOV PC,LR

LTORG ;声明文字池,此地址存储0x12345678

… ;其它代码

LTORG 伪指令常放在无条件跳转指令之后,或者子程序返回指令之后,这样处理器就不会错误地将文字池中的数据当作指令来执行。

MAP

MAP 用于定义一个结构化的内存表的首地址。此时,内存表的位置计数器{VAR}设置为该地址值{VAR}为汇编器的内置变量。^与MAP 同义。

伪指令格式:

MAP expr,{base_register}

其中:expr 数字表达式或程序中的标号。当指令中没有

base_register 时,expr 即为结构化内存表的首地址。

base_register 一个寄存器。当指令中包含这一项时,结构化内存表的首地址为expr 与base_register 寄存器值的和。

伪指令应用举例如下:

MAP 0x00,R9 ;定义内存表的首地址为R9

Timer FIELD 4 ;定义数据域Timer,长度为4 字节

Attrib FIELD 4 ;定义数据域Attrib,长度为4 字节

String FIELD 100 ;定义数据域String,长度为100 字节

ADR R9,DataStart ;设置R9 的值,即设置结构化的内存表地址

LDR R0,Atrrib ;相当于LDR,R0,[R9,#4]

MAP 伪指令和FIELD 伪指令配合使用,用于定义结构化的内存表结构。MAP 伪指令中的base-register 寄存器的值对于其后所有的FIELD 伪指令定义的数据域是默认使用的,直到遇到新的包含base-register 项的MAP 伪指令。

FIELD

FIELD 用于定义一个结构化内存表中的数据域。#与FIELD 同义。

伪指令格式:

{tabel} FIELD expr

其中:label 当指令中包含这一项时,label 的值为当前内存表的位置计数器{VAR}的值,汇编编译器处理了这条FIELD 伪指令后,内存表计数器的值将加上expr。

expr 表示本数据域在内存表中所占用的字节数。

伪指令应用举例如下:

MAP 0x40003000 ;内存表的首地址为0x40003000

count1 FIELD 4 ;定义数据域count1,长度为4 字节

count2 FIELD 4 ;定义数据域count2,长度为4 字节

count3 FIELD 4 ;定义数据域count3,长度为4 字节

LDR R1,count1 ;R1=[0x40003000+0x00]

STR R1,count2 ;[0x40003000+0x00]=R1

MAP、FIELD 伪指令仅仅是定义数据结构,它们并不实际分配内存单元。

SPACE

SPACE 用于分配一块内存单元,并用0 初始化。%与SPACE 同义。

伪指令格式:

{label} SPACE expr

其中:label 内存块起始地址标号。

expr 所要分配的内存字节数。

伪指令应用举例如下:

AREA DataRA,DATA,READWROTE ;声明一数据段,名为DataRAM

DataBuf SPACE 1000 ;分配1000 字节空间

DCB

DCB 用于分配一段字节内存单元,并用伪指令中的expr 初始化。一般可用来定义数据表格,或文字符串。=与DCB 同义。

伪指令格式:

{label} DCB expr{,expr}{,expr}…

其中:label 内存块起始地址标号。

expr 可以为-128~255 的数值或字符串。内存分配的字节数由expr 个数决定。

伪指令应用举例如下

DISPTAB DCB 0x33,0x43,0x76,0x12

DCB -120,20,36,55

ERRSTR DCB “Send,data is error!”,0

DCD 和DCDU

DCD 用于分配一段字内存单元,并用伪指令中的expr 初始化。DCD 伪指令分配的内存需要字对齐,一般可用来定义数据表格或其它常数。&与DCD 同义。

DCDU 用于分配一段字内存单元,并用伪指令中的expr 初始化。DCD 伪指令分配的内存不需要字对齐,一般可用来定义数据表格或其它常数。

伪指令格式:

{label} DCD expr{,expr}{,expr}…

{label} DCDU expr{,expr}{,expr}…

其中:label 内存块起始地址标号。

expr 常数表达式或程序中的标号。内存分配字节数由expr 个数决定。

伪指令应用举例如下:

Vectors

LDR PC,ReserAddr

LDR PC,UndefinedAddr

ResetAddr DCD Reset

UndefinedAddr DCD Undefined

Reset

Undefined

DCDO

DCDO 用于分配一段字内存单元。并将每个单元的内容初始化为该单元相对于静态基址寄存器的偏移量。DCDO 伪指令作为基于静态基址寄存器R9 的偏移量分配内存单元。DCDO 伪指令分配的内存需要字对齐。

伪指令格式:

{label} DCDO expr{,expr}{,expr}…

其中:label 内存块起始地址标号。

expr 地址偏移表达式或程序中的标号。内存分配的字数由expr 个数决定。

伪指令应用举例如下:

IMPORT externsym

DCDO externsym ;分配32 位的字单元,其值为标号externsym 基于R9 的偏移

DCFD 和DCFDU

DCFD 用于分配一段双字的内存单元,并用双精度的浮点数据fpliteral 初始化。每个双精度的浮点数占据两个字单元。DCFD 伪指令分配的内存需要字对齐。

DCFDU 具有DCFD 同样的功能,但分配的内存不需要字对齐。

伪指令格式:

{label} DCFD fpliteral{,fpliteral}{,fpliteral}…

{label} DCFDU fpliteral{,fpliteral}{,fpliteral}…

其中:label 内存块起始地址标号。

fpliteral 双精度的浮点数。

伪指令应用举例如下:

DCFD 2E30,-3E-20

DCFDU -.1,1000,2.1E18

DCFS 和DCFSU

DCFS 用于分配一段字的内存单元,并用单精度的浮点数据fpliteral 初始化。每个单精度的浮点数占据一个字单元。DCFD 伪指令分配的内存需要字对齐。

DCFSU 具有DCFS 同样的功能,但分配的内存不需要字对齐。

伪指令格式:

{label} DCFS fpliteral{,fpliteral}{,fpliteral}…

{label} DCFSU fpliteral{,fpliteral}{,fpliteral}…

其中:label 内存块起始地址标号

fpliteral 单精度的浮点数。

伪指令应用举例如下:

DCFS 1.1E2,-1.3E10,0.0999

DCI

在ARM 代码中,DCI 用于分配一段字节的内存单元,用指定的数据expr 初始化。指定内存单元存放的是代码,而不是数据。

在Thumb 代码中,DCI 用于分配一段半字节的内存单元,用指定的数据expr 初始化。指定内存单元存放的是代码,而不是数据。

伪指令格式:

{label} DCI expr

其中:label 内存块起始地址标号。

expr 可为数字表达式。

DCI 伪指令和DCD 伪指令非常类似,不同之处在于DCI 分配的内存中的数据被标识为指令。可用于通过宏指令业定义处理器不支持的指令。

伪指令应用举例如下:

MACRO ;宏定义(定义NEWCMN Rd,Rn 指令)

NEWCMN $Rd,$Rm ;宏名为NEWCMN,参数为Rd 和Rm

DCI 0xe16a0e20:OR:($Rd:SHL:12):OR:$Rm

MEND

DCQ 和DCQU

DCQ 用于分配一段双字的内存单元,并用64 位的整数数据literal 初始化。DCQ 伪指令分配的内存需要字对齐。

DCQU 具有DCQ 同样的功能,但分配的内存不需要字对齐。

伪指令格式:

{label} DCQ {-}literal{,{-}{literal}}…

{label} DCQU {-}literal{,{-}{literal}}…

其中:label 内存块起始地址标号。

literal 64 位的数字表达式。取值范围为0~264-1 当literal前有“.”号时,取值范围为-263~-1 之间。

伪指令应用举例如下:

DCQU 1234,-76568798776

DCW 和DCWU

DCW 用于分配一段字的内存单元,并用指定的数据expr 初始化。DCW 伪指令分配的内存需要字对齐。

DCWU 具有DCW 同样的功能,但分配的内存不需要字对齐。

伪指令格式:

{label} DCW expr{,expr}{,expr}…

{label} DCWU expr{,expr}{,expr}…

其中:label 内存块起始地址标号。

expr 数字表达式,取值范围为-32768~65535。

伪指令应用举例如下:

DCW -592,123,6756

报告伪指令

报告伪指令用于汇编报告指示。该类伪指令如下:

断言错误:ASSERT。

汇编诊断信息显示:INFO。

设置列表选项:OPT。

插入标题:TTL 和SUBT。

ASSERT

ASSERT 为断言错误伪指令。在汇编编译器对汇编程序的第二遍扫描中,如果其中

ASSERT 条件不成立,ASSERT 伪指令将报告该错误信息。

伪指令格式:

ASSERT Logical_expr

其中:Logical_expr 用于断言的逻辑表达式

伪指令应用举例如下:

ASSERT Top<>Temp ;断言Top 不等于Temp

INFO

汇编诊断信息显示伪指令,在汇编器处理过程中的第一遍扫描或第一遍扫描时报告诊断信息。

伪指令格式:

INFO numeric_expr,string_expr

其中:numeric_expr 数据表达式。若值为0,则在第一遍扫描时报告诊断信息。否则在第一遍扫描时报告诊断信息。

strint_expr 要显示的字串

伪指令应用举例如下:

INFO 0,”Version 0。1” ;在第二遍扫描时,报告版本信息

if cont1 > cont2 ;如果cont1 > cont2

INFO 1,”cont1 > cont2” ;则在第一遍扫描时报告”cont1 > cont2”

OPT

设置列表选项伪指令。通过OPT 伪指令可以在源程序中设置列表选项。

伪指令格式:

OPI n

其中n 所设置的选项的编码如下:

1 设置常规列表选项

2 关闭常规列表选项

4 设置分页符,在新的一页开始显示

8 将行号重新设置为0

16 设置选项,显示SET、GBL、LCL 伪指令

32 设置选项,不显示SET、GBL、LCL 伪指令

64 设置选项,显示宏展开

128 设置选项,不显示宏展开

256 设置选顶,显示宏调用

512 设置先项,不显示宏调用

1024 设置选顶,显示第一遍扫描列表

2048 设置选项,不显示第一遍扫描列表

4096 设置选项目,显示条件汇编伪指令

8192 设置选项,不显示条件汇编伪指令

16384 设置选项,显示MEND 伪指令

32768 设置选项,不显示MEND 伪

默认情况下,-list 选项生成常规的列表文件,包括变量声明,宏展开,条件汇编伪指令及MEND 伪指令,而且列表文件只是在第二遍扫描时给出,通过OPT 伪指令,可以在源程序中改变默认的选项。

伪指令应用举例如下:

… ;代码

OPT 512 ;不显示宏调用

… ;代码

TTL 和SUBT

TTL 和SUBT 为插入标题伪指令。

TTL 伪指令在列表文件的每一页的开头插入一个标题。该TTL 伪指令的作用在其后的每一页,直到遇到新的TTL 伪指令。

SUBT 伪指令在列表文件的每页的开头第一个子标题。该SUBT 伪指令的作用在其后的每一页,直到遇到新的SUBT 伪指令。

伪指令格式:

TTL title

SUBT subtitle

其中:title 标题名。

subtitle 子标题名。

伪指令应用举例如下:

TTL mainc

SUBT subc con

A.4.3  汇编控制伪指令

汇编控制伪指令用于条件汇编、宏定义、重复汇编控制等。该类伪指令如下:

条件汇编控制: IF、ELSE 和ENDIF

宏定义: MACRO 和MEND

重复汇编: WHILE 及WEND

IF、ELSE 和ENDIF

IF 、ELSE 和ENDIF 伪指令能够根据条件把一段代码包括在汇编程序内或将其排除在程序之外。

[与IF 同义,|与ELSE 同义,]与ENDIF 同义。

伪指令格式:

IF logical_expr

;指令或伪指令代码段1

ELSE

;指令或伪指令代码段2

ENDIF

其中:logical_expr 用于控制的逻辑表达式。若条件成立,则代码段落在汇编源程序中有效。若条件不成立,代码段1 无效,同时若使用ELSE 伪指令,代码段有效。

伪指令应用举例如下:

IF {CONFIG}=16

BNE __rt_udiv_1

LDR R0,=__rt_div0

BX R0

ELSE

BEQ __rt_div0

ENDIF

IF、ELSE 和ENDIF 伪指令是可以嵌套使用的。

MACRO 和MEND

MACRO 和MEND 伪指令用于宏定义。MACRO 标识宏定义的开始,MEND 标识宏定义久的结束。用MACRO 及MEND 定义的一段代码,称为宏定义体。这样在程序中就可以通过宏指令多次调用该代码段。

伪指令格式:

MACRO

{$label} macroname {$parameter} {$parameter}…

;宏定义体。

MEND

其中:$label 宏指令被展开时,label 可被替换成相应的符号,通常为一个标号在一个符号前使用$表示被汇编时将使用相应的值替代$后的符号。

macroname 所定义的宏的名称。

$parameter 宏指令的参数。当宏指令被展开时将被替换成相应的值,类似于函数中的形式参数。

对于子程序代码比较短,而需要传递的参数比较多的情况下可以使用汇编技术。首先要用MACR 和MEND 伪指令定义宏,包括宏定义体代码。在MACRO 伪指令之后的第一行声明宏的原型,其中包含该宏定义的名称,及需要的参数。在汇编程序中可以通过该宏定义的名称来调用它。当源程序被汇编时,汇编编译器将展开每个宏调用,用宏定义体代替源程序中的宏定义的名称,并用实际的参数值代替宏定义时的形式参数。

伪指令应用举例如下:

MACRO

CSI_SETB ;宏名为CSI_SETB,无参数

LDR R0,=rPDATG ;读取GPG0 口的值

LDR R1,[R0]

ORR R1,R1#0x01 ;CSI 置位操作

STR R1,[R0] ;输出控制

MEND

带参数的宏定义如程序清单:

MACRO

$IRQ_Label HANDLER $IRQ_Exception

EXPORT $IRQ_Label

IMPORT $IRQ_Exception

$IRQ_Label

SUB LR,LR,#4

STMFD SP!,{R0-R3,R12,LR}

MRS R3,STSR

STMFD SP!,{R3}

MEND

WHIL 和WEND

WHILE 和WEND 伪指令用于根据条件重复汇编相同的或几乎相同的一段源程序。

伪指令格式:

WHILE logical_expr

;指令或伪指令代码段

WEND

其中:logical_expr 用于控制的逻辑表达式。若条件成立,则代码段在汇编源程序中有效,并不断重复这段代码直到条件不成立。

伪指令应用举例如下:

WHILE no<5

no SETA no+1

WEND

WHILE 和WEND 伪指令是可以嵌套使用的。

A.4.5  杂项伪指令

杂项伪指令在汇编编程设计较为常用,如段定义伪指令,入口点设置伪指令,包含文件伪指令,标号导出或引入声明等,该类伪指令如下:

边界对齐: ALIGN。

段定义: AREA。

指令集定义: CODE16 和CODE32。

汇编结束: END。

程序入口: ENTRY。

常量定义: EQU。

声明一个符号可以被其它文件引用:EXPORT 和GLORBAL。

声明一个外部符号:IMPORT 和EXTERN。

包含文件:GET 和INCLUDE。

包含不被汇编的文件:INCBIN。

保留符号表中的局部符号:KEEP。

禁止浮点指令:NOFP。

指示两段之间的依赖关系:REQUIRE。

堆栈8 字节对准:PEQUIRE8 和PRESERVE8。

给特定的寄存器命名:RN。

标记局部标号使用范围的界限:ROUT。

ALIGN

ALIGN 伪指令通过添加补丁字节使当前位置满足一定的对齐方式。

伪指令格式:

ALIGN {expr{,offset}}

其中:expr 数字表达式,用于指定对齐的方式。取值为2 的n 次幂,如1、2、4、8等,不能为0 其没有expr,则默认为字对齐方式。

offset 数字表达式,当前位置对齐到下面形式的地址处:offset+n*expr

在下面的情况中,需要特定的地址对齐方式:

(A)Thumb 伪指令ADR 要求地址是字对齐的。而Thumb 代码中地址标号可能不是字对齐的。这时就要使用伪指令ALIGN4 使Thumb 代码中地址标号为字对齐。

(B)由于有些ARM 处理器的Cache 采用了其他对齐方式。如16 字节对齐方式,这时使用ALIGN 伪指令指定合适的对齐方式可以充分发挥Cache 的性能优势。

(C)LDRD 和STRD 指令要求存储单元为8 字节对齐。这样在为LDRD/STRD 指令分配的存储单元前要使用伪指令ALIGN8 实现8 字节对齐方式。

(D)地址标号通常自身没有对齐要求,而在ARM 代码中要求地起标号对齐是字对齐的,Thumb 代码中要求半字对齐。这样可以使用ALIGN4 和ALIGN2 伪指令来调整对齐方式。

伪指令应用举例如下。

通过ALIGN 伪指令使程序中的地址标号字对齐:

AREA Example,CODE,READONLY ;声明代码段Example

START LDR R0,=Sdfjk

MOV PC,LR

Sdfjk DCB 0x58 ;定义一字节存储空间,字对齐方式被破坏

ALIGN ;声明字对齐

SUBI MOV R1,R3 ;其它代码

MOV PC,LR

在段定义AREA 中,也可使用ALIGN 伪指令对齐,但表达式的数字含义是同的

AREA MyStack,DATA,NOINIT,ALIGN=2 ;声明数据段

;MyStack,并重新字对齐

IrqStackSpace SPACE IRQ_STACK_LEGTH*4 ;中断模式堆栈空间

FiqStackSpace SPACE FIQ_STACK_LEGTH*4 ;快速中断模式堆栈空间

AbtStackSpace SPACE ABT_STACK_LEGTH*4 ;中止义模式堆栈空间

UndtStackSpace SPACE UND_STACK_LEGTH*4 ;未定义模式堆栈

将两个字节的数据放在同一个字的第一个字节和第四个字节中,带offset 的ALIGN对齐:

AREA offsetFxample, CODE

DCB 0x31 ;第一个字节保存0x31

ALIGN 4,3 ;字对齐

DCB 0x32 ;第四个字节保存0x32

AREA

AREA 伪指令用于定义一个代码段或数据段。ARM 汇编程序设计采用分段式设计,一个ARM 源程序至少需要一个代码段,大的程序可以包含多少个代码段及数据段。

伪指令格式:

AREA sectionname{,attr}{,attr}…

其中:sectionname 所定义的代码段或数据段的名称。如果该名称是以数据开头的,则该名称必须用“|”括起来,如|1_datasec|。还有一些代码段具有的约定的名称。如|text|表示C 语言编译器产生的代码段或者与C 语言库相关的代码段。

attr 该代码段或数据段的属性。

在AREA 伪指令中,各属性之间用逗号隔开。以下为段属性及相关说明:

ALIGN = expr。默认的情况下,ELF 的代码段和数据段是4 字节对齐的,expr 可以取0~31 的数值,相应的对齐方为2expr 字节对齐。如expr=3 时为字节对齐。对于代码段,expr 不能为0 或1。

ASSOC = section。指定与本段相关的ELF 段。任何时候连接section 段也必须包括sectionname 段。

DODE 为定义代码段。默认属性为READONLY。

COMDEF 定义一个通用的段。该段可以包含代码或者数据。在其它源文件中,同名的COMDEF 段必须相同。

COMMON 定义一个通用的段。该段不包含任何用户代码和数据,连接器将其初始化为此。各源文件中同名的COMMON 段共用同样的内存单元,连接器为其分配合适的尺寸。

DATA 为定义段。默认属性为READWRITE。

NOINIT 指定本数据段仅仅保留了内存单元,而没有将各初始写入内存单元,或者将内存单元值初始化为0。

READONLY 指定本段为只读,代码段的默认属性为READONLY。

READWRITE 指定本段为可读可写。数据段的默认属性为READWRITE。

使用AREA 伪指令将程序分为多个ELF 格式的段,段名称可以相同, 这时同名的段被放在同一个ELF 段中。

伪指令应用举例如下:

AREA Example ,CODE,READNOLY ;声明一个代码,名为Example

CODE16 和CODE32

CODE16 伪指令指示汇编编译器后面的指令为16 位的Thumb 指令。

CODE32 伪指令指示汇编编译器后面的指令为32 位的ARM 指令。

伪指令格式:

CODE16

CODE32

CODE16 和CODE32 伪指令只是指示汇编编译器后面的指令的类型,伪指令本身并不进行程序状态的切换。要进行状态切换,可以使用BX 指令操作。

伪指令应用举例如下:

AREA Example CODE,READONLY

CODE32

使用CODE16 和CODE32 定义Thumb 指令及ARM 指令并用BX 指令进行切换。

CODE16 和CODE32 的使用:

AREA ArmThumC,CODE,READONLY

CODE32

ADR R0,ThumbStart+1

BX R0

CODE16

ThumbStart

MOV R0,#10

END

END

END 伪指令用于指示汇编编译器源文件已结束。每一个汇编源文件均要使用一个END 伪指令,指示本源程序结束。

伪指令格式:

END

ENTRY

ENTRY 伪指令用于指定程序的入口点。

伪指令格式:

ENTRY

一个程序(可以包含多个源文件)中至少要有一个ENTRY,可以有多个ENTRY。但一个源文件中最多只有一个ENTRY。

伪指令应用举例如下。

AREA, Example, CODE,READNOLY

ENTRY

CODE32

START MOV R1,#0x5F

EQU

EQU 伪指令为数字常量,基于寄存器的值和程序中的标号定义一个名称。*与EQU同义。

指令格式:

name EQU expr{,type}

其中:name 要定义的常量的名称。

expr 基于寄存器的地址值,程序中的标号,32 位地址常量或32 位常量。

type 当expr 为32 位常量时,可用type 指示expr 表示的数据类型。如下示例:

CODE16

CODE32

DATA

EQU 伪指令的作用类似于C 语言中的#define。用于为一个常量定义名称。

伪指令应用举例如下:

T_bit EQU 0x20 ;定义常量T_bit,其值为0x20

PLLCON EQU 0xE01FC080 ;定义寄存器PLLCON,地址为0Xe01F080

ABCD EQU label+8 ;定义ABCD 为label+8

EXPORT 和GLOBAL

EXPORT 声明一个符号可以被其它文件引用。相当于声明了一个全局变量。

GLOBAL 与EXPORT 相同

指令格式:

EXPORT symbol{[WEAK]}

GLOBAL symbol{[WEAK]}

其中:symbol 要声明的符号名称

[WEAK] 声明其它的同名符优先于本符号被引用。

伪指令应用举例如下:

EXPORT InitStack

GLOBAL Vectors

IMPORT 和EXTERN

IMJPORT 伪指令指示编译器当前的符号不是在本源文件中定义的,而是在其他源文件中定义的,在本源文件中可能引用该符号。

EXTERN 与IMPORT 相同

指令格式:

IMPORT symbol{[WEAK]}

EXTERN symbol{[WEAK]}

其中:symbol 要声明的符号名称。

[WEAK] 指定该选项后,如果symbol 在所有的源程序中都没有被定义,编译器也不会生任何错误信息,同时编译器也不会到当前没有被INCLUDE 进来库中去查找该标号。

使用IMPORT 或EXTERN 声明外部标号时,若连接器在连接处理时不能解释该符号,而伪指令中没有[WEAK]选项,则连接器会报告错误,若伪指令中有[WEAK]选项,则连接器不会报告错误,而是进行下面的操作:

(A)如果该符号被B 或者BL 指令引用,则该符号被设置成下一条指令的地址,该B 或者BL 指令相当于一条NOP 指令。

(B)其它情况下该符号被设置0。

伪指令应用举例如下:

IMPORT InitStack

EXTERN Vectors

GET 和INCLUDE

GET 伪指令将一个源文件包含到当前源文件中,并将被包含的文件在当前位置进行汇编处理。INCLUDE 与GFT 同义。

指令格式:

GET filename

INCLUDE filename

其中:filename 要包含的源文件名,可以使用路径信息。

GET 伪指令通常用于包含一些宏定义或常量定义的源文件。如用EQU 定义的常量,用MAP 和FIELD 定义的结构化的数据类型,这样的源文件类似于C 语言中的头文件,GET、INCLUDE 伪指令不能用来包含目标文件,而INCBIN 伪指令可以包含目标文件。

伪指令应用举例如下:

INCLUDE LPC2106.inc

INCBIN

INCBIN 伪指令将一个文件包含到当前源文件中,而被包含的文件不进行汇编处理。

指令格式:

INCBIN filename

其中:filename 要包含的源文件名,可以使用路径信息。

通常可以使用INCBIN 将一个执行文件或者任意数据包含到当前文件中,被包含的执行文件或数据将被原封不动地放下当前文件中,编译器从INCBIN 伪指令后面开始继续处理。

伪指令应用举例如下:

NCBIN charlib。bin

KEEP

KEEP 伪指令指示编译器保留符号表中的局部符号。

伪指令格式:

KEEP {symbol}

其中:symbol 要保留的局部标号。若没有此项,则除了基于寄存器处的所有符号将包含在目标文件的符号表中。

NOFP

NOFP 伪指令用于禁止源程序中包含浮点运算指令。

伪指令格式:

NOFP

REQUIRE

REQUIRE 伪指令指定段之间的依赖关系。

伪指令格式:

REQUIRE label

其中:label 所需要的标号的名称。

当进行链接处理时,包含了REQUIRE label 伪指令的源文件,则定义label 的源文件也被包含。

PEQUIRE8 和PRESERVE8

PEQUIRE8 伪指令指示当前文件请求堆栈为8 字节对齐。

PRESERVE8 伪指令指示当前文件保持堆栈为8 字节对齐。

伪指令格式:

PEQUIRE8

PRESERVE8

链接器保证要求8 字节对齐的堆栈只能被堆栈为8 字的对齐的代码调用

阅读(3963) | 评论(0) | 转发(0) |

给主人留下些什么吧!~~

评论热议

请登录后评论。

linux 汇编 preserve8,ARM汇编伪指令相关推荐

  1. linux 汇编与arm汇编,C语言与ARM汇编混编

    __asm__ __volatile__内嵌汇编用法简述 在阅读C/C++原码时经常会遇到内联汇编的情况,下面简要介绍下__asm__ __volatile__内嵌汇编用法.因为我们华清远见教学平台是 ...

  2. arm gnu linux系统,GNU ARM汇编

    在大学的时候,汇编就是学的很烂.一是对汇编这门语言没概念,二是那些指令集很难记清楚,用的机会也少,自然学的不好.但是现在觉得相当有必要重头学习一下汇编.部分原因我在上一篇写完设备模型的总结时提到了而. ...

  3. arm汇编 调用linux中断,GNU ARM汇编(四)中断汇编之非嵌套中断处理

    原标题:GNU ARM汇编(四)中断汇编之非嵌套中断处理 在写这篇blog之前,不得不感慨一句:纸上得来终觉浅,绝知此事要躬行.作为EE出身的,虽然好久好久没用汇编写 的中断了,但自我感觉对中断的理解 ...

  4. 【嵌入式开发】 ARM 汇编 (指令分类 | 伪指令 | 协处理器访问指令)

    作者 : 韩曙亮 博客地址 : http://blog.csdn.net/shulianghan/article/details/42408137  转载请著名出处 本博客相关文档下载 :  -- A ...

  5. linux 嵌入式汇编 adc,嵌入式Linux ARM汇编(四)——ARM汇编程序设计

    嵌入式Linux ARM汇编(四)--ARM汇编程序设计 汇编程序有顺序.循环.分支.子程序四种结构形式. 一.顺序结构 程序实例: AREA Buf,DATA,READWRITE;定义数据段Buf ...

  6. ARM 汇编基础教程番外篇 ——配置实验环境

    From:https://zhuanlan.zhihu.com/p/29145513 win10 arm 汇编环境 Windows 平台下搭建 ARM 汇编集成环境:https://jingyan.b ...

  7. ARM汇编与ARM GNU汇编 区别

    一.想学汇编,at&t汇编与ARM汇编的区别? 问:想学汇编语言,因为现在用的是linux系统(ubuntu 11.04),so 有一本<汇编语言程序设计>马朝晖译,可惜淘宝.当当 ...

  8. arm汇编的学习笔记,对比x86和arm(1)-从最简单的函数谈起

    最简单的函数 x86下汇编指令 ARM下汇编指令 Hello World x86中汇编指令 ARM汇编 LDM/STM指令 LDMFD 指令 ADR指令: 知识点扩展: ADR ADRL: LDR指令 ...

  9. linux汇编伪指令大全,ARM汇编伪指令

    分类: LINUX 2009-10-21 16:39:09 ARM 汇编程序的由机器指令,伪指令和宏指令组成.伪指令不像机器指令那样在处理器运行期间由机器执行,而是汇编程序对源程序汇编期间由汇编程序处 ...

最新文章

  1. 危害企业IT系统最严重的五个安全威胁
  2. python手机版代码-Python手机号码归属地查询代码
  3. TCP第四次挥手为什么要等待2MSL(最长报文段寿命,Maximum Segment Lifetime)
  4. Python列表List
  5. Redis 写磁盘出错 Cannot allocate memory
  6. 2022春节法律思维
  7. ReentrantLock 公平锁和非公平锁加锁和解锁源码分析(简述)
  8. 仿MIUI音量变化环形进度条实现
  9. wordpress在Linux nginx下权限设置
  10. vs2005/vs2008 快捷键【转】
  11. Spark案例实战教程
  12. 5 分钟掌握智联招聘网站爬取并保存到 MongoDB 数据库
  13. 构建最基础的Spring项目及所需要的jar包
  14. android抢qq红包源码,QQ抢红包插件实现,安卓源码,以及详细分析,androidqq抢红包源码,捡代码论坛整理...
  15. Netty权威指南 第2版
  16. TCP/IP常见英文缩写
  17. 对java.lang.UnsupportedOperationException 异常的分析
  18. PSB格式转换太麻烦?Aspose.PSD教你用代码将大型PSB文件转换为PDF/JPEG格式
  19. 洲际酒店集团大中华区开业酒店突破600家;因美纳中国生产制造基地正式启用 | 美通企业日报...
  20. python 矢量场的构造、计算;通过 matplotlib 作图、分析、筛选符合要求的像素点

热门文章

  1. Android横向滑动加载更多的控件的实现---HorizontalScrollSlideView
  2. 【WEB】Web性能压力测试工具
  3. matlab求hession矩阵
  4. Service Test1
  5. 如何打造优秀的个人博客
  6. bootstrap使用及解析
  7. Linux fsck命令详解
  8. shiro反序列化漏洞学习(工具+原理+复现)
  9. 宽带信号的DOA估计学习笔记(四):空间分辨率
  10. 数据处理方法-算术编码(香农算法、java编码实现)