第一个汇编程序

通过前几篇文章,我们逐步建立了学习汇编语言之前需要的基础知识。接下来,在这篇文章中,我们开始编写我们的第一个汇编程序了。

编辑器,汇编器与链接器

工欲善其事,必先利其器。我们编写汇编语言,至少需要编辑器、汇编器和链接器。编辑器,就是提供语法高亮、智能缩进、自动补全等功能的文本编辑软件,汇编器与链接器则是汇编语言需要的核心装备,其功能我会在接下来的几篇文章中提到。我使用的编辑器是Visual Studio Code, 汇编器是自带的as, 链接器也是自带的ld。除了编辑器以外,汇编器和链接器应该都是macOS自带的,无需额外安装。

第一个程序

我们在编辑器中输入如下语句,并在自己的目录下保存为5-basic.s.

# 5-basic.s
    .section    __TEXT,__text
    .globl  _main
    .p2align    2
_main:
    mov    w0, #0
    ret

然后在终端下进入该目录,键入如下命令:

as 5-basic.s -o 5-basic.o

然后再键入(关于这个指令为什么这么复杂,我在macOS上使用链接器的正确姿势中详细论证了其必要性与正确性)

ld 5-basic.o -lSystem -L $(xcrun --show-sdk-path -sdk macosx)/usr/lib -o 5-basic

此时该目录下应该会有一个叫5-basic的可执行文件,我们在终端下运行它:

./5-basic

然后,什么都没有发生,程序自动退出了。大功告成!

关于这个程序的解释,我决定下篇文章再讲。这篇文章接下来的篇幅,我打算谈一谈汇编器与汇编语法。

汇编语法

汇编语言是机器码的human-readable版本。虽说如此,汇编语法之间也会有细微的区别。AArch64的汇编器主要有两种语法:armasm的和GNU的。这两种语法有细微的区别。我这篇文章中主要用的是GNU语法,这也是用的最广泛的语法。

GCC与LLVM

我们知道,对于一门编程语言来说,它有对应的编译器和调试器。对于编译器来说,在类Unix系统上主要有两大阵营:GCC和LLVM. GCC包括C编译器gcc、调试器gdb等,LLVM项目包括C编译器clang、调试器lldb等。这些现代的编译器架构,都是将编译过程分为前端和后端,无论是在什么平台、什么CPU架构下,编译器前端都是相同的,将源代码编译成中间代码(GCC为RTL,LLVM为LLVM中间码(IR))。而后端则是将IR再翻译成对应操作系统中对应CPU架构下的可执行文件。因此,如果有a种语言,b个操作系统和c个CPU架构,那么现在的编译器就不再需要设计abc种代码,而一共需要a种前端和bc种后端,最终效果是只需要a+bc种编译器代码。

对于高级编程语言,GCC与LLVM的竞争主要在于编译的优化、效率等,但是对于汇编语言,由于其可以直译机器码,所以并不存在汇编器优化,因此,在机器码层面,GCC和LLVM是等效的。在这一系列文章中我使用的汇编器as是LLVM的汇编器, 调试器是LLVM的lldb.

GCC套件是GNU操作系统的一个部分,GNU是开源的、社区驱动的。而LLVM项目也是开源的,现在主要是Apple在投资运行。因此,既然在macOS上,我就主要用的是LLVM系的工具。