跳到主要内容

5. 汇编文件输出

本章介绍如何使用 clang汇编源代码。

5.1 汇编示例​

KF32工具链兼容GNU语法的汇编伪指令。关于更多的伪指令,可参考GNU Binutils文档。

以下示例展示了汇编代码,用于计算两个变量的和。

.text
.file "add.c"
.globl add
.p2align 3
.type add,@function
add:
ADD r0, r1, r0
JMP lr

使用kf32clang来汇编语言源代码。通常,调用kf32clang的步骤如下:

kf32clang --target=kf32r -o file.o file.s

5.2 汇编流程​

默认情况下,clang 使用汇编代码源文件后缀来决定是否运行 C 预处理器:

  • .s(小写)后缀表示不需要预处理的汇编代码。
  • .S(大写)后缀表示需要预处理的汇编代码。-x 选项允许显式指定后续输入文件的编程语言来覆盖默认配置,而不是通过文件后缀进行推断。具体来说,-x assembler-with-cpp表示汇编代码包含 C 预处理器指令,clang 必须运行 C 预处理器。-x 选项只适用于命令行中在该选项之后的输入文件,一旦使用了 -x 选项,它就会为其后的所有输入文件设置编程语言,直到遇到下一个 -x 选项或文件列表结束。

注意:不要将 .ifdef 汇编器指令与预处理器 #ifdef 指令混淆:

  • 预处理器 #ifdef 指令检查是否存在预处理器宏。这些宏通过 #define 预处理器指令或 clang命令行选项 -D 定义。
  • clang 汇编 .ifdef 指令检查代码符号。这些符号通过标签或 .set 指令定义。

汇编.S文件时,预处理器先运行,对源代码进行文本替换,对 #ifdef 指令的处理阶段。之后源代码会传递给汇编器,对 .ifdef 指令进行处理。

汇编源文件中的注释应使用 // 或 /* */。# 是立即数的前缀(如 MOV r0, #16),不能用作注释:写在语句之后会报 Unexpected Immediate;写在行首时,.S 文件由预处理器先行处理,若该行恰好以 #error、#define、#include、#if 等指令名开头,预处理器会把它当作真正的预处理指令执行,而 .s 文件不经过预处理,整行只被汇编器当作注释忽略。因此 .s 与 .S 对以 # 开头的行处理结果不同,编写注释请勿依赖这一差别。

要预处理汇编代码源文件,请执行以下其中之一:

  1. 确保汇编代码文件名为 .S后缀,然后使用:

    kf32clang --target=kf32r -march=kf32r test.S -c -o test.o
  2. 使用 -x assembler-with-cpp 选项来告诉 clang 汇编源文件需要预处理。当你已有带有小写后缀的源文件时,这个选项非常有用。例如:

    kf32clang --target=kf32r -march=kf32r -x assembler-with-cpp test.s -c -o test.o