# 3.2.3 关于格式的注解
GCC 产生的汇编代码对我们来说有点儿难读。一方面,它包含一些我们不需要关心的信息,另一方面,它不提供任何程序的描述或它是如何工作的描述。例如,假设我们用如下命令生成文件 mstore.s:
linux> gcc -Og -S mstore.c
mstore.s 的完整内容如下:
.file "010-mstore.c"
.text
.globl multstore
.type multstore, @function
multstore:
pushq %rbx
movq %rdx, %rbx
call mult2
movq %rax, (%rbx)
popq %rbx
ret
.size multstore, .-multstore
.ident "GCC: (Ubuntu 4.8.1-2ubuntu1~12.04) 4.8.1"
.section .note.GNU-stack,"",@progbits
所有以 . 开头的行都是指导汇编器和链接器工作的伪指令。我们通常可以忽略这些行。另一方面,也没有关于指令的用途以及它们与源代码之间关系的解释说明。
为了更清楚地说明汇编代码,我们用这样一种格式来表示汇编代码,它省略了大部分伪指令,但包括行号和解释性说明。对于我们的示例,带解释的汇编代码如下:
void multstore(long x, long y, long *dest)
x in %rdi, y in %rsi, dest in %rdx
1 multstore:
2 pushq %rbx Save %rbx
3 movq %rdx, %rbx Copy dest to %rbx
4 call mult2 Call mult2(x, y)
5 movq %rax, (%rbx) Store result at *dest
6 popq %rbx Restore %rbx
7 ret Return
通常我们只会给出与讨论内容相关的代码行。每一行的左边都有编号供引用,右边是注释,简单地描述指令的效果以及它与原始 C 语言代码中的计算操作的关系。这是一种汇编语言程序员写代码的风格。
我们还提供网络旁注,为专门的机器语言爱好者提供一些资料。一个网络旁注描述的是 IA32 机器代码。有了 x86-64 的背景,学习 IA32 会相当简单。另外一个网络旁注简要描述了在 C 语言中插入汇编代码的方法。对于一些应用程序,程序员必须用汇编代码来访问机器的低级特性。一种方法是用汇编代码编写整个函数,在链接阶段把它们和 C 函数组合起来。另一种方法是利用 GCC 的支持,直接在 C 程序中嵌入汇编代码。
旁注:ATT 与 Intel 汇编代码格式
我们的表述是 ATT(根据 “AT&T” 命名的,AT&T 是运营贝尔实验室多年的公司)格式的汇编代码,这是 GCC、OBJDUMP 和其他一些我们使用的工具的默认格式。其他一些编程工具,包括 Microsoft 的工具,以及来自 Intel 的文档,其汇编代码都是 Intel 格式的。这两种格式在许多方面有所不同。例如,使用下述命令行,GCC 可以产生
multstore函数的 Intel 格式的代码:linux> gcc -Og -S -masm=intel mstore.c这个命令得到下列汇编代码:
multstore: push rbx mov rbx, rdx call mult2 mov QWORD PTR [rbx], rax pop rbx ret我们看到 Intel 和 ATT 格式在如下方面有所不同:
- Intel 代码省略了指示大小的后缀。我们看到指令
push和mov,而不是pushq和movq。- Intel 代码省略了寄存器名字前面的
%符号,用的是rbx,而不是%rbx。- Intel 代码用不同的方式来描述内存中的位置,例如是
QWORD PTR [rbx]而不是(%rbx)。- 在带有多个操作数的指令情况下,列出操作数的顺序相反。当在两种格式之间进行转换的时候,这一点非常令人困惑。
虽然在我们的表述中不使用 Intel 格式,但是在来自 Intel 和 Microsoft 的文档中,你会遇到它。
网络旁注 ASM:EASM:把 C 程序和汇编代码结合起来
虽然 C 编译器在把程序中表达的计算转换到机器代码方面表现出色,但是仍然有一些机器特性是 C 程序访问不到的。例如,每次 x86-64 处理器执行算术或逻辑运算时,如果得到的运算结果的低 8 位中有偶数个 1,那么就会把一个名为 PF 的 1 位条件码(condition code)标志设置为 1,否则就设置为 0。这里的 PF 表示 “parity flag(奇偶标志)”。在 C 语言中计算这个信息需要至少 7 次移位、掩码和异或运算(参见习题 2.65)。即使作为每次算术或逻辑运算的一部分,硬件都完成了这项计算,而 C 程序却无法知道 PF 条件码标志的值。在程序中插入几条汇编代码指令就能很容易地完成这项任务。
在 C 程序中插入汇编代码有两种方法。第一种是,我们可以编写完整的函数,放进一个独立的汇编代码文件中,让汇编器和链接器把它和用 C 语言书写的代码合并起来。第二种方法是,我们可以使用 GCC 的内联汇编(inline assembly)特性,用
asm伪指令可以在 C 程序中包含简短的汇编代码。这种方法的好处是减少了与机器相关的代码量。当然,在 C 程序中包含汇编代码使得这些代码与某类特殊的机器相关(例如 x86-64),所以只应该在想要的特性只能以此种方式才能访问到时才使用它。
← 3.2.2 代码示例 3.3 数据格式 →