跳到主要内容

7. 编译工具汇编器

本章介绍KF32工具链的汇编器功能。

汇编源文件与 C 源文件一样,由编译器 kf32clang 统一处理(kf32clang --target=kf32r -march=kf32r -c xxx.s,见 2.6 使用汇编器)。本章介绍的指令与伪指令在该汇编过程中均受支持。

7.1 汇编器的主要特性​

汇编器支持指令、伪指令以及用户定义的宏,具体包括以下内容:

  • KungFu32通用指令集的汇编语言
  • KungFu32指令集提供的伪指令
  • GNUC常规通用伪指令及Clang汇编伪指令
  • 用户定义的宏

7.2 命令行语法​

汇编源文件(.s/.S)由 kf32clang 处理,需要指定目标与架构:

kf32clang --target=kf32r -march=kf32r -c add.s

其中 --target 指定目标(当前必须为 kf32r),-march 指定架构,-c 表示只汇编、不链接。该命令生成目标文件 add.o,随后可由 kf32ld 链接(见 2.6)。

7.3 常用伪指令介绍​

7.3.1 .section​

section用于指定类型。

在C语言中,将函数或变量放入由“name”指定的段。

例如:

void __attribute__((section(".new_sect1"))) foo()
{
return;
}

函数foo将被放入.new_sect1段。

unsigned int var __attribute__((section(".new_sect2")));

变量var将被放入.new_sect2段。

常见的段定义为 text (flash空间), data(RAM空间)。

在汇编语言中,直接使用伪指令section进行段类型定义,如:

.section .text$_NMI_exception
.section .text
.section .indata

需要注意的是汇编语言没有准确的函数概念,即section对后面的代码仍然有效,除非遇到新的section声明。

7.3.2 .global symbol,​

.global 使符号symbol对连接器ld可见。如果您在局部过程中定义符号symbol,其它和此的局部过程都可以访问它的值。另外,symbol从连接到本过程的另一个文件中的同名符号获取自己的属性。另外可以使用 .export 进行辅助变量的描述。

7.3.3 .align abs-expr, abs-expr, abs-expr​

增加位置计数器(在当前的子段)使它指向规定的存储边界。

第一个表达式参数(结果必须是纯粹的数字)是必需参数:边界基准,见后面的描述。

第二个表达式参数(结果必须是纯粹的数字)给出填充字节的值,用这个值填充位置计数器越过的地方。这个参数(和逗点)可以省略,如果省略它,填充字节的值通常是0。但在某些系统上,如果本段标识为包含代码,而填充值被省略,则使用no-op指令填充这个空间。

第三个参数表达式的结果也必须是纯粹的数字,这个参数是可选的。如果存在第3个参数,它代表本对齐命令允许越过字节数的最大值。如果完成这个对齐需要跳过的字节比指定的最大值还多,则根本无法完成对齐。您可以在边界基准后简单地使用两个逗号,以省略填充值参数(第二参数);如果您想在适当的时候,对齐操作自动使用no-op指令填充,这个方法将非常奏效。

第一个表达式是对齐边界以2为底的指数,即对齐到 2^N 字节。例如 .align 3 向后移动位置计数器至8的倍数(与 .p2align 3 等价)。如果地址已经满足对齐要求,则无需移动。

7.3.4 .byte expressions​

.byte 可不带参数或者带多个表达式参数,表达式之间由逗点分隔。每个表达式参数都被汇编成下一个字节。

7.3.5 .word expressions​

.word 本命令可不带表达式或带多个表达式,这些表达式可以属于任意段,每个表达式由逗号分隔。

汇编生成的数字的大小,字节顺序视生成程序运行的目标机器而定。

7.3.6 .short expressions​

.short 本命令通常和 .word 命令一样。

7.3.7 .int expressions​

.int 可以不带参数或带多个expressions,参数之间由逗号分隔。每个expressions都生成一个数字,这个数字等于表达式在目标机器运行时的值。字节顺序和数字的位数视汇编的目标机器而定。

7.3.8 .long expressions​

.long 是 .int 的等价命令。

7.3.9 .fill repeat, size, value​

.fill 该汇编指令会产生数个(repeat个)大小为size字节的重复拷贝。大小值size可以为0或者某个值,但是若size大于8,则限定为8。每个重复字节内容取自一个8字节数。高4字节值为0,低4字节为数值value。这3个参数都是绝对值,size和value是可选的。如果第二个逗号和value省略,value默认值为0;如果后两个参数都省略,则size默认值为1。如 .fill 1,1 对应一个字节的0值,往往对应全局未初始化变量的内容表达。

7.3.10 .type name , type description​

.type 本命令经常用来设置符号name的类型(属性)为函数符号或是目标符号两者之一。type description部分允许使用5种不同的语法,以兼容众多的汇编器。这些语法是:

.type <name>,#function
.type <name>,#object
.type <name>,@function
.type <name>,@object
.type <name>,%function
.type <name>,%object
.type <name>,"function"
.type <name>,"object"

注:STT_FUNCTION/STT_OBJECT 形式(如 .type <name> STT_FUNCTION)不被支持。

7.3.11 .size name , expression​

.size 本命令经常用来设置符号name的内存大小。内存大小的单位是字节,通过计算参数expression得到,参数expression中可以使用标签进行计算。本命令常用来设置函数符号的长度。

7.3.12 .if absolute expression​

.if 标志着一段代码的开始,这段代码只有在参数absolute experession(必须是一个独立的表达式)不为0时才进行汇编。这段条件汇编代码必须使用 .endif 标志结束。另外,可以使用 .else 来标记一个代码块,这个代码块与前面那段代码只有一个会进行汇编。如果您需要检查数个汇编条件,可以使用 .elseif 命令,以避免在 .else 代码块中进行if/else语句块的嵌套。

同样可以使用下面 .if 的变体:

  • .ifdef symbol 如果指定的符号symbol已经定义过,汇编下面那段代码。
  • .ifc string1,string2 如果两个字符串相同的话,汇编下面那段代码。字符串可以可选地使用单引号。如果不使用引号则第1个字符串在逗号处结束。第2个字符串在本行末结束。包含空白的字符串应该使用引号标注。字符串比较时是区分大小写的。
  • .ifeq absolute expression 如果参数的值为0,汇编下面那段代码。
  • .ifeqs string1,string2 这是 .ifc 的另一种形式,字符串必须使用双引号标注。
  • .ifge absolute expression 如果参数的值大于等于0,汇编下面那段代码。
  • .ifgt absolute expression 如果参数的值大于0,汇编下面那段代码。
  • .ifle absolute expression 如果参数的值小于等于0,汇编下面那段代码。
  • .iflt absolute expression 如果参数的值小于0,汇编下面那段代码。
  • .ifnc string1,string2 类似于 .ifc,不过使用反向的测试:如果两个字符串不相等的话,汇编下面那段代码。
  • .ifndef symbol / .ifnotdef symbol 如果指定的符号symbol不曾被定义过,汇编下面那段代码。上面两种写法是等效的。
  • .ifne absolute expression 如果参数的值为不等于0,汇编下面那段代码(换句话说,这是 .if 的另一种写法)。
  • .ifnes string1,string2 类似于 .ifeqs,不过使用反向的测试:如果两个字符串不相等的话,汇编下面那段代码。

7.3.13 .else​

.else 是条件汇编指令之一;如果前面 .if 命令的条件不成立,则表示需要汇编 .else 后的一段代码。

7.3.14 .elseif​

.elseif 是条件汇编指令之一。它可以在 .else 段中快速产生一个新的 .if 块。

7.3.15 .endif​

.endif 是条件汇编指令之一。它标志着条件汇编代码块的结束。

7.3.16 .set symbol, expression​

.set 设置symbol为expression。这将改变symbol的值域和类型领域以符合expression参数。如果symbol已被标志为external,则symbol保持它的标志。

您可以在同一个汇编程序中多次使用 .set 命令来设置同一个符号。

如果设置一个全局符号,该符号在目标文件中值为最后设定的值。

7.3.17 .end​

.end 标记着汇编文件的结束。汇编器不处理 .end 命令后的任何语句。