以下内容源于网络资源的学习与整理,如有侵权请告知删除。
(1)代码格式
ARM GNU汇编中,每行的代码格式如下:
[
(2)格式说明
- Instruction表示指令,Directive表示伪操作,pseudo-instruction表示伪指令。
- @comment表示注释语句。
(1)书写规范
ARM GNU汇编指令中的标号只能由点号、大小写字母、数字、下划线等字符组成,除局部标号外,不能以数字开头。
(2)标号的本质
标号label本质上代表它所在行的地址,因此也可以当作变量或者函数来使用。段内标号的地址值在汇编时确定,段外标号的地址值在连接时确定。
(3)标号的分类
根据标号的生成方式,可以将标号分为三类:
1)基于PC的标号。基于PC的标号是位于目标指令前的标号或者程序中数据定义伪操作前的标号。这种标号在汇编时将被处理成PC值加上或减去一个数字常量,常用于表示跳转指令”b”等的目标地址,或者代码段中所嵌入的少量数据。
2)基于寄存器的标号。基于寄存器的标号常用MAP和FIELD来定义,也可以用EQU来定义。这种标号在汇编时将被处理成寄存器的值加上或减去一个数字常量,常用于访问数据段中的数据。
3)基于绝对地址的标号。绝对地址是一个32位数据。它可以寻址的范围为[0x00000000,0xFFFFFFFF],即可以直接寻址整个内存空间。
(4)局部标号的使用说明
局部标号主要在局部范围内使用,而且局部标号可以重复出现。它由两部组成:开头是一个0-99直接的数字,后面紧接一个通常表示该局部标号作用范围的符号。局部标号的作用范围通常为当前段,也可以用ROUT来定义局部标号的作用范围。
1)局部标号定义的语法格式:N{routname}
- 其中N表示0~99之间的数字。
- routname表示当前局部范围的名称,通常为该标号作用范围的名称(用ROUT伪操作定义)。
2)局部标号引用的语法格式:%{F|B}{A|T}N{routname}
- %:表示引用操作
- N:为局部标号的数字号
- routname:为当前作用范围的名称(用ROUT伪操作定义的)
- F:指示编译器只向前搜索
- B:指示编译器只向后搜索
- A:指示编译器搜索宏的所有嵌套层次
- T:指示编译器搜索宏的当前层次
3)下面是使用局部标号的例子,一段循环程序。
1: subs r0, r0, #1 @每次循环使r0=r0-1 bne 1F @跳转到1标号去执行如果F和B都没有指定,编译器先向前搜索,再向后搜索。如果A和T都没有指定,编译器搜索所有从当前层次到宏的最高层次,比当前层次低的层次不再搜索。
如果指定了routname,编译器向前搜索最近的ROUT伪操作,若routname与该ROUT伪操作定义的名称不匹配,编译器报告错误,汇编失败。
(1)段的格式
ARM GNU汇编中通过伪操作.section来自定义一个段,格式如下:
.section section_name [, "flags"[, %type[,flag_specific_arguments]]]
(2)格式说明
- Section_name,表示段名。
- Flags,表示ELF格式允许的段标志,可以为 a(可分配)、w(可写段)、x(执行段)。
- Type,表示段类型。
- flag_specific_arguments,用来指定参数内容。
(3)段的范围
每一个段以段名为开始,以下一个段名或者文件结尾为结束。
除了允许用户自定义一个段,ARM GNU汇编系统也有一些预定义好的段名。
段名 描述 .text 代码段 .data 初始化数据段 .bss 未初始化数据段 …… …… (1).section .data
这种段包含程序已初始化的数据,即包含那些具有初值的变量,例如:
.section .data hello : .string "Hello world!\n" hello_len : .long 13(2) .section .bss
这个段包含程序还未初始化的数据,即包含那些没有初值的变量。当操作系统装入这个程序时将把这些变量都置为 0,即使你在.bss节给一个变量赋初值,这个值也会丢失,并且变量的值仍为0。例如下面这个程序被装入时,name 和 name_len 都被置为 0。
.section .bss name : .fill 30 name_len : .long 0使用.bss 比使用.data 的优势在于,.bss段不占用磁盘的空间。在磁盘上一个长整数就足以存放.bss段,当程序被装入到内存时,操作系统也只给这个段分配4个字节的内存大小。
编译程序一般把.data 和.bss 在4字节上对齐,例如.data段如果总共有34个字节,编译程序会把它对齐到36 字节上,也就是说实际给它36字节的空间。
(3).section .text
这个段包含程序的代码,它是只读段,而.data 和.bss 是读/写节。
执行代码一般放于.text段,需要读写的数据放于.data段,只读数据放于.rodata段,未初始化数据放于.bss段。注意,.bss段应该在.text段之前。
(1)汇编程序的默认入口是_start标号。
(2)用户也可以在链接脚本xxx.lds中用ENTRY标志指明其它入口点。
(3)下面是定义入口点的模板。
.section .data < initialized data here> .section .bss < uninitialized data here> .section .text .globl _start _start:
(1)使用伪操作.macro来完成宏定义,其格式如下:
.macro 宏名 参数名列表 @伪操作.macro定义一个宏 宏体 .endm @.endm表示宏结束(2)如果宏使用参数,那么在宏体中使用该参数时要添加前缀“\”。
(3)宏定义时的参数还可以使用默认值。
(4)可以使用.exitm伪指令来退出宏。
进制 描述 举例 二进制 以0b或者0B开头 八进制 以0开头 如0456,0123 十进制 以非0数字开头 如1234,9865 十六进制 以0x开头 如0xaeff,0x124f
字符串常量需要使用引号括起来,中间也可以使用转义字符,如 “You are welcome!\n”。
在汇编程序中,当前指令的地址,可以用符号“.”来表示。
在汇编程序中,表达式可以使用常数或者数值, “-”表示取负数,“~”表示取补,其他符号如+、-、*、 /、%、<、<<、>、>>、|、&、^、!、==、>=、<=、&&、||跟C语言中的用法相似。
见博客ARM官方汇编与ARM GNU汇编中的伪操作中ARM GNU汇编伪操作部分。
寄存器的名称如下:
简称 全名 R0~R15 通用寄存器 FP(R11) 帧指针寄存器 SP(R13) 栈指针寄存器 LR(R14) 链接寄存器 PC(R15) 程序计数器 xPSR, xPSR_all, xPSR_f, xPSR_x,
xPSR_ctl, xPSR_fs,xPSR_fx, xPSR_f,
xPSR_cs, xPSR_cf, xPSR_cx
程序状态寄存器