ARM官方汇编器与GNU汇编器中的伪操作

丁理
2023-12-01

以下内容源于网络资源的学习与整理,如有侵权请告知删除。

参考博客

(1)嵌入式Linux ARM汇编

(2)GNU ARM 汇编基础 - wanli1024 - 博客园

(3)GNU ARM 汇编简介_niepangu的博客-CSDN博客

(4)ARM编译器(一)ARM汇编与ARM GNU汇编 | 骏的世界

(5)GNU ARM汇编伪操作(Directives) 命令集 - Leo Chin - 博客园

(6)GNU ARM指令伪操作_Volatile_xian的博客-CSDN博客

前言

汇编器用于将汇编语言文件转化为二进制的目标文件,目前常用的ARM汇编器有以下两种:

(1)ARM公司的汇编器,适合在Windows平台下使用。

(2)GNU工具链中的汇编器,适合于Linux开发平台。

不同的汇编器对汇编语言的语法要求不一样。GNU汇编器是GNU工具集的一部分,针对的是多种处理器架构,这意味着GNU汇编器的语法不同于ARM公司汇编器的语法。但是实际上两者的汇编指令基本相同(见博文ARM官方汇编指令),只是伪操作不同,因此文本主要说明ARM官方汇编器和GNU汇编器中的伪操作。

一、ARM官方汇编器中的伪操作

1、AREA

(1)格式:AREA 段名 属性1,属性2,…,属性n

(2)作用:定义一个代码段或数据段。

(3)特别说明:

  • 段名若以数字开头,则该段名需用“|”括起来,比如“ |1_test| ”。
  • 属性字段表示这个段的相关属性,多个属性用逗号分隔。

属性

描述

CODE

用于定义代码段,默认为READONLY。

DATA

用于定义数据段,默认为READWRITE。

READONLY

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

READWRITE

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

ALIGN

使用方式为ALIGN表达式。可执行文件的代码段和数据段默认是按字对齐的,表达式的取值范围为0~31,相应的对齐方式为2表达式次方。

COMMON

该属性定义一个通用的段,不包含任何的用户代码和数据。各源文件中同名的COMMON段共享同一段存储单元。

(4)代码示例:

AREA Init,CODE,READONLY ;定义了一个代码段,段名为Init,属性为只读。

2、ALIGN

(1)格式:ALIGN{表达式 { ,偏移量}}

(2)作用:通过添加填充字节的方式,使当前位置满足一定的对其方式。

(3)特别说明:表达式的值用于指定对齐方式,可能的取值为2的幂,如1、2、4、8、16等。若未指定表达式,则将当前位置对齐到下一个字的位置。偏移量也为一个数字表达式,若使用该字段,则当前位置的对齐方式为:2的表达式次幂+偏移量。另外注意,在AREA中使用和单独使用ALIGN时,格式与对齐的计算方式不一样(见代码示例)。

(4)代码示例:

@例子1
AREA Init,CODE,READONLY,ALIGN=3  @指定后面的指令为8字节对齐
;.... 
END

@例子2
ALIGN  4  表示4字节地址对齐

3、CODE16、CODE32       

(1)格式:CODE16(或CODE32 )

(2)作用:CODE16(或CODE32 )伪指令通知编译器,其后的指令序列为16位的Thumb指令(或32位的ARM指令)。

(3)特别说明:若在汇编源程序中同时包含ARM指令和Thumb指令时,可用CODE16伪指令通知编译器其后的指令序列为16位的Thumb指令,用CODE32伪指令通知编译器其后的指令序列为32位的ARM指令。因此,在使用ARM指令和Thumb指令混合编程的代码里,可用这两条伪指令进行切换,但注意它们只通知编译器其后指令的类型,并不能对处理器进行状态的切换。            

(4)代码示例:

AREA Init,CODE,READONLY            
;....      
CODE32               @通知编译器其后的指令为32位的ARM指令
LDR R0,=NEXT+1     @将跳转地址放入寄存器R0      
BX R0                @程序跳转到新的位置执行,并将处理器切换到Thumb工作状态
;....     
CODE16               @通知编译器其后的指令为16位的Thumb指令
NEXT LDR R3,=0x3FF            
;....     
END                  @程序结束

4、ENTRY

(1)格式:ENTRY

(2)作用:用于指定汇编程序的入口点。

(3)特别说明:在一个完整的汇编程序中至少要有一个ENTRY,也可以有多个(此时程序的真正入口点由链接器指定),但在一个源文件里最多只能有一个ENTRY(可以没有)。

(4)代码示例:

AREA Init,CODE,READONLY
ENTRY ;指定应用程序的入口点
;.....

5、END       

(1)格式:END

(2)作用:用于通知编译器已经到了源程序的结尾。

(3)代码示例:

AREA Init,CODE,READONLY
;......
END @指定应用程序的结尾

6、EXPORT

(1)格式:EXPORT 标号 [,WEAK]

(2)作用:声明一个全局标号,其他源文件可以使用这个标号。WEAK表示碰上其他同名标号时,其他标号优先。

7、IMPORT

(1)格式:IMPORT 标号,[,WEAK]

(2)作用:表示当前文件中引用的标号在其他源文件中。WEAK表示找不到该标号时也不报错,一般将该标号置为0,如果是B 或BL指令用到该标号,该指令置为nop。

(3)特别说明:该标号会加入到当前源文件的符号表中。

8、EXTERN

(1)格式:EXTERN 标号,[,WEAK]

(2)作用:和IMPORT一样,但如果当前文件没有引用该标号,该标号不会加入到当前源文件的符号表中。

9、GET(或INCLUDE)

(1)格式:INCLUDE pathname

(2)作用:将一个源文件包含到当前的源文件中。

10、EQU

(1)格式:name EQU expression

(2)作用:对一个常量标号赋值,等同于C语言中用#define定义一个常量

(3)特别说明:name是符号名, expression是寄存器相关或者程序相关的固定值。

(4)代码示例:

num EQU 2  ;为符号num赋值为2

11、SPCAE

(1)格式: {label} SPACE expr

(2)作用:用于分配一片连续内存单元,并用0初始化。

(3)特别说明:SPACE可用%代替;label是一个标号, 可选;expr是分配的内存字节数。

(4)代码示例:

stack SPACE 100 ;分配100个字节内存单元,并用0初始化。标号stack是这片空间的起始地址

12、DCB

(1)格式:{label} DCB expr {,expr}

(2)作用:用于分配段字节内存单元,并用伪操作中的expr初始化。

(3)特别说明:label是一个标号,可选;expr可以是-128~255的数值或者字符串。

(4)代码示例:

string DCB "HELLO"  ;为HELLO字符串分配空间,string是这块空间的起始地址

13、DCD(或DCDU)

(1)格式: {label} DCD expr, {,expr}

(2)作用:用于分配段字内存单元(分配的内存都是字对齐,DCDU并不严格字对齐),并用伪操作中的expr初始化。

(3)特别说明:label是一个标号,可选,表示这块内存单元的首地址。expr是数字表达式或程序中的标号。DCD 可用 & 代替。

(4)代码示例:

data DCD 1,2,3,4     ;分配字对齐的字单元空间,并初始化为1、2、3、4

​14、更多伪操作

伪操作

语法格式

作用

GBLA

GBLA  Varible

声明一个全局的算术变量,并将其初始化为0

GBLL

GBLL  Varible

声明一个全局的逻辑变量,并将其初始化成{FALSE}

GBLS

GBLS  Varible

声明一个全局的字符串变量,并将其初始化成空串

LCLA

LCLA  Varible

声明一个局部的算术变量,并将其初始化为0

LCLL

LCLL  Varible

声明一个局部的逻辑变量,并将其初始化成{FALSE}

LCLS

LCLS  Varible

声明一个局部的字符串变量,并将其初始化成空串

SETA

SETA  Varible  expr

给一个全局或局部算术变量赋值

SETL

SETL  Varible  expr

给一个全局或局部逻辑变量赋值

SETS

SETS  Varible  expr

给一个全局或局部字符串变量赋值

RLIST

name LIST {list of registers}

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

CN

name CN expr

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

CP

name CP expr

为一个协处理器定义名称

DN/SN

name DN/SN expr

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

FN

name FN  expr

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

LTORG

LTONG

声明一个数据缓冲池(文字池)的开始

MAP

MAP expr {, base-register}

定义一个结构化的内存表(storage map)的首地址

FIELD

{label}  FIELF  expr

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

SPACE

{label}  SPACE  expr

分配一块连续内存单元,并用0初始化

DCB

{label}  DCB  expr {,expr}..

分配一块字节内存单元,并用expr初始化

DCD/ DCDU

{label} DCD/DCDU expr {,expr}…

分配一块字内存单元, 并用expr初始化

DCDO

{label}  DCDO  expr {,expr}…

分配一块字对齐的字内存单元, 并用expr初始化

DCFD/DCFDU

{label}   DCFD{U}   fpliteral

,{,fpliteral}…

为双精度的浮点数分配字对齐的内存单元

DCFS/DCFSU

{label}    DCFS{U}  fpliteral

,{,fpliteral}…

为单精度的浮点数分配字对齐的内存单元

DCI

{label} DCI expr, {expr}…

ARM代码分配一段字对齐的内存单元,填充expr(二进制指令码),THUMB代码中,分配一段半字对齐的半字内存单元。

DCQ/ DCQU

{label} DCQ{U}  {-} literal,

{, {-} literal}…

分配一段以双字(8个字节)为单位的内存

DCW/DCWU

{label} DCW{U}  {-} literal,

{, {-} literal}…

DCW用于分配一段半字对齐的半字内存单元

二、ARM GNU汇编器中的伪操作

(1)ARM GNU汇编中的伪操作,一般都以“.”开头。

(2)ARM GNU汇编中的伪操作,可以分为以下几类。

  • 数据定义伪操作
  • 符号定义伪操作
  • 代码控制伪操作
  • 预定义控制伪操作
  • 其他伪操作

1、数据定义伪操作

常见的数据定义伪操作如表格所示。

数据定义伪操作格式作用举例与备注

.byte

.byte expr {,expr}…

分配一段字节内存单元,并用expr初始化。即定义单字节数据。

.byte 1,2,0b01,0x34,072,'s'

.hword/.short

.hword expr {,expr}…

分配一段半字内存单元,并用expr初始化。即定义双字节数据

.short 0x1234

.ascii

.ascii expr {,expr}…

定义字符串expr(不会自动增加/0结束符,需要自行添加结尾字符'\0'。)

.ascii "welcome\0"

.asciz/.string

.asciz expr {,expr}…

定义字符串expr(会自动增加/0为结束符)

.string "abcd", "efgh", "hello!"

.asciz "qwer", "sun", "world!"

.floar/.single

.float expr {,expr}…

分配一段字内存单元,并用32位IEEE单精度浮点数expr初始化内存单元

.double

.doubel expr {,expr}…

定义64bit IEEE浮点数expr

.word/.long/.int

.word expr {,expr}…

分配一段字内存单元,并用expr初始化

.long 0x12345678

.fill

.fill  repeat {,size} {,value}

分配一段字节内存单元,用size个字节value填充repeat次(size默认为1,value默认为0)

.zero

.zero size

分配一段size个字节的内存单元,并用0填充内存

.space/.skip

.space size, {,value}

分配一段size个字节的内存单元,用value将内存初始化

.quad.qua expr {,expr}…分配一段双字内存单元,并用expr初始化双字内存单元.quad 0x1234567890abcd
.octa.octa expr{,expr}…分配一段四字内存单元,并用expr初始化四字内存单元
.ltorg.ltorg声明一个数据缓冲池(literal pool),即在当前段的当前地址(字对齐)产生一个文字池
.int.int expressions定义一个整型。

2、符号定义伪操作

常见的符号定义伪操作如表格所示。

符号定义伪操作格式作用举例与备注
.equ / .set.equ symbol,expr将symbol定义为expr.equ abc 3         @即abc=3
.equiv.equiv symbol        将symbol定义为expr,若symbol已定义则出错
.global/.globl.globl symbol将symbol定义为全局标号
.extern.extern symbol声明symbol为一个外部变量

3、代码控制伪操作

常见的代码控制伪操作如表格所示。

代码控制伪操作

格式

作用

举例与备注

.section

.section expr

定义一个段,expr可以是.text、.data、.bss

.text

.text {subsection}

将定义符开始的代码编译到代码段或代码子段(subsection)

.data

.data{subsection}

将定义符开始的代码编译到数据段或数据子段(subsection)

.bss

.bss{subsection}

将变量存放到.bss段或.bss的子段(subsection)

.cond 16/.thumb

.code 16/.thumb

表示之后的汇编指令使用THUMB指令集

.code 32/.arm

.code 32/.arm

表示之后的汇编指令使用ARM指令集

.end

.end

标记汇编文件的结束

.include

.include "filename"

将一个源文件包含到当前源文件中

.align/.balign

.align {alignment} {,fill},{max}

通过填充字节使当前位置满足一定的对齐格式

比如“ .balignl 4 0xdeadbeef ”表示4字节对齐,l表示以四字节为单位填充,填充的内容是0xdeadbeef。
.org.org offset{,expr}

 指定从当前地址加上offset开始存放代码,并且从当前地址到当前地址加上offset之间的内存单元,用零或指定的数据进行填充

 4、预定义控制伪操作

常见的预定义控制伪操作如下所示。
宏定义伪操作格式作用举例与备注

.macro

标识宏定义的开始用.macro及.endm定义一段代码,称为宏定义体。
.exitm中途跳转出宏
.endm标识宏定义的结束
.if 条件判断语句
.else条件判断语句
.endif条件结束语句
.include     .include "file_name"包含文件标识 
.incbin.incbin "file"[,skip[,count]]

将原封不动地一个二进制文件编译到当前文件中。

skip表明是从文件开始处跳过skip个字节开始读取文件,count是读取的字数。

5、其他伪操作         

伪操作格式作用举例与备注
.err.err使编译结果产生错误报告
.eject.eject在汇编符号列表文件中插入一分页符
.list .list 产生汇编列表(从.list到.nolist)
.nolist.nolist汇编列表结束处。再次使用.list产生汇编列表
.title.title "title_name"使用title_name作为标题
.sbttl.sbttl "title_name" 使用title_name作为子标题
.print .print string打印输出信息到标准输出
.fail.fail expr编译汇编文件时产生警告
.reqreq name, expr为一个特定的寄存器定义名称
.unreq.unreq 寄存器别名取消一个寄存器的别名。注意被取消的别名必须事先定义过,否则编译器就会报错。这个伪操作也可以用来取消系统预制的别名。
.rept

.rept 重复次数

数据定义

.endr @结束重复定义

重复定义伪操作。

.rept 3

.byte 0x23

.endr

相当于

.byte 0x23

.byte 0x23

.byte 0x23

三、两者的区别与联系

ARM官方汇编、ARM GNU汇编,它们的伪操作的区别与联系如下。

两种开发环境下的汇编代码,有较多不同的点,主要是符号及伪操作的不同。

ARM官方汇编伪操作ARM GNU汇编伪操作

备注

;

@

注释

#0x

#&

十六进制立即数

IFDEF、IF

.ifdef、.if

不完全相同

ELSE

.else

ELSEIF

.elseif

ENDIF

.endif

LTORG

.ltorg

OR

|

OR

AND

&

AND

SHL

<<

Shift left

SHR

>>

Shift right

MACRO

.macro

开始宏

END.end

MEND

.endm

结束宏

INCLUDE

.include

DCB

.word

定义一个字数据

DCW

.short

DCD

.long

DCB

.byte

RN

.req

EXPORT.global

GBLA.global
IMPORT.extern
ENTRYENTRY:
CODE16.thumb
CODE32.arm
%.fill
NUM SETA 16.equ  NUM,16
NUM EQU 25.equ  NUM,25

AREA WORD, CODE, READONLY

.text

AREA BLOCK, DATE, READWRITE

.data

 类似资料: