1.4 RISC-V汇编程序伪操作
在汇编语言中,有一些特殊的操作助记符,这些操作的助记符通常被称为伪操作(Pseudo Ops),伪操作在汇编程序中的作用是指导汇编器处理汇编程序的行为,这些伪操作仅在汇编过程中起作用,一旦汇编结束,伪操作的使命就此结束。
由于本文介绍的RISC-V工具链是GCC工具链,因此,一般的GNU汇编语法中定义的伪操作均可在RISC-V汇编语言中使用。经过不断的增加,目前GNU汇编中定义的伪操作数目众多,感兴趣的读者可以自行查阅完整的GNU汇编语法手册了解详情。本节将仅简介若干常见的伪操作。
.file filename
.file伪操作用指示汇编器该汇编程序的逻辑文件名。
.global symbol_name或者.globl symbol_name
global和.globl伪操作用于定义一个全局的符号,使得链接器能够全局识别它,即一个程序文件中定义的符号能够被所有其他程序文件可见。
.local symbol_name
.local伪操作用于定义局部符号,使得此符号不能够被其他程序文件可见。
.weak symbol_name
在汇编程序中,符号的默认属性为强(strong),.weak伪操作则用于设置符号的属性为弱(weak),如果此符号之前没有定义过,则同时创建此符号并定义其属性为weak。
如果符号的属性为weak,那么它无需定义具体的内容。在链接的过程中,另外一个属性为strong的同名符号可以将此weak符号的内容强制覆盖。利用此特性,.weak伪操作常用于预先预留一个空符号,使得其能够通过汇编器语法检查,但是在后续的程序中定义符号的真正实体,并且在链接阶段将空符号覆盖并链接。
.type name , type description
.type伪操作用于定义符号的类型。譬如“.type symbol,@function”即将名为symbol的符号定义为一个函数(function)。
.align integer
.align伪操作用于将当前PC地址推进到“2的integer次方个字节”对齐的位置。譬如“.align 3”即表示将当前PC地址推进到8个字节对齐的位置处。
.balign integer
.balign伪操作用于将当前PC地址推进到“integer个字节”对齐的位置。
.zero integer
.zero伪操作将从当前PC地址处开始分配integer个字节空间并且用0值填充。譬如“.zero 3”即表示分配三个字节的0值。
.byte expression [, expression]*
.byte伪操作将从当前PC地址处开始分配若干个字节(byte)的空间,每个字节填充的值由分号分隔开的expression指定。
.2byte expression [, expression]*
.2byte伪操作将从当前PC地址处开始分配若干个双字节(2 bytes)的空间,每个双字节填充的值由分号分隔开的expression指定。空间分配的地址可以与双字节非对齐。
.4byte expression [, expression]*
.4byte伪操作将从当前PC地址处开始分配若干个四字节(4 bytes)的空间,每个四字节填充的值由分号分隔开的expression指定。空间分配的地址可以与四字节非对齐。
.8byte expression [, expression]*
.8byte伪操作将从当前PC地址处开始分配若干个八字节(8 bytes)的空间,每个八字节填充的值由分号分隔开的expression指定。空间分配的地址可以与八字节非对齐。
.half expression [, expression]*
.half伪操作将从当前PC地址处开始分配若干个半字(half-word)的空间,每个半字填充的值由分号分隔开的expression指定。空间分配的地址一定与半字对齐(half-word aligned)。
.word expression [, expression]*
.word伪操作将从当前PC地址处开始分配若干个字(word)的空间,每个字填充的值由分号分隔开的expression指定。空间分配的地址一定与字对齐(word aligned)。
.dword expression [, expression]*
.dword伪操作将从当前PC地址处开始分配若干个双字(double-word)的空间,每个双字填充的值由分号分隔开的expression指定。空间分配的地址一定与双字对齐(double-word aligned)。
.string “string”
.string伪操作将从当前PC地址处开始分配若干个字节空间用于存放“string”字符串。字节的个数取决于字符串的长度。
.float 或者 .double expression [, expression]*
.float伪操作将从当前PC地址处开始分配若干个单精度浮点数(32位)的空间,每个单精度浮点数填充的值由分号分隔开的expression指定。空间分配的地址一定与32位对齐。
.double伪操作将从当前PC地址处开始分配若干个双精度浮点数(64位)的空间,每个双精度浮点数填充的值由分号分隔开的expression指定。空间分配的地址一定与64位对齐。
若干.float和.double伪操作的示例如下:
- .comm或者.common name, length
.comm和.common伪操作用于声明一个名为name的未初始化存储区间,区间大小为length个字节。由于是未初始化存储区间,在链接阶 段会将其链接到.bss段中。有关链接后ELF文件常见段.text、.data、.rodata、.bss请参见本号之前发表文章《编译过程简介》节了解更多信息。
- .option {rvc,norvc,push,pop}
-
.option伪操作用于设定某些架构特定的选项,使得汇编器能够识别此选项并按照选项的定义采取相应的行为。
-
rvc、norvc是RISC-V架构特有的选项,用于控制是否生成16位宽的压缩指令:
-
“.option rvc”伪操作表示接下来的汇编程序可以被汇编生成16位宽的压缩指令。
-
“.option norvc”伪操作表示接下来的汇编程序不可以被汇编生成16位宽的压缩指令。
-
-
push、pop用于临时性的保存或者恢复.option伪操作指定的选项:
-
“.option push”伪操作暂时将当前的选项设置保存起来,从而允许之后使用.option伪操作指定新的选项;而“.option pop”伪操作将最近保存的选项设置恢复出来重新生效。
-
通过“.option push”和“.option pop”的组合,便可以在汇编程序中在不影响全局选项设置的情况下,为其中嵌入的某一段代码特别地设置不同的选项。
-
- .section name [, subsection]
.section伪操作指明将接下来的代码汇编链接到名为name的段(Section)当中,还可以指定可选的子段(Subsection)。常见的段如.text、.data、.rodata、.bss:
-
“.section .text”伪操作将接下来的代码汇编链接到.text段。
-
“.section .data”伪操作将接下来的代码汇编链接到.data段。
-
“.section .rodata”伪操作将接下来的代码汇编链接到.rodata段。
-
“.section .bss”伪操作将接下来的代码汇编链接到.bss段。
- .text
.text伪操作基本等效于“.section .text”。
- .data
.data伪操作基本等效于“.section .data”。
- .rodata
.rodata伪操作基本等效于“.section .rodata”。
- .bss
.bss伪操作基本等效于“.section .bss”。
-
.pushsection name 和.popsection
-
.pushsection伪操作将之前的段设置保存起来,并且将当前的段设置改为名为name的段。即,指明将接下来的代码汇编链接到名为name的段中。
-
.popsection伪操作将最近保存的段设置恢复出来。
-
通过“.pushsection”和“.popsection”的组合,便可以在汇编程序的编写过程中,在某一个段的汇编代码中特别的插入另外一个段的代码。这种编写方式在某些情况下会给代码编写带来极大的方便,示例代码如下:
-
网友评论