汇编语言可以表达非常底层的操作
你可以访问机器相关的寄存器和 I/O
你可以控制关键代码段的确切行为,否则这些代码段可能会导致多个软件线程或硬件设备之间的死锁
你可以打破常用编译器的约定,这可能会允许一些优化(例如暂时打破关于内存分配、线程、调用约定等的规则)
你可以构建使用不兼容约定的代码片段之间的接口(例如,由不同的编译器生成,或由底层接口分隔)
你可以访问处理器的不寻常编程模式(例如,16 位模式,用于连接 Intel PC 上的启动代码、固件或遗留代码)
你可以为紧凑循环生成相当快的代码,以应对糟糕的非优化编译器(但现在,有免费的优化编译器可用!)
你可以生成为你的特定硬件设置完美调优的手工优化代码,但对其他人的硬件设置则不然
你可以为你的新语言的优化编译器编写一些代码(这是极少数人会做的事情,即使他们做也不会经常做)
也就是说,你可以完全控制你的代码
汇编语言是一种非常底层的语言(仅高于手写二进制指令模式)。这意味着
初始编写时冗长且乏味
非常容易出错
你的错误可能很难追踪
你的代码可能相当难以理解和修改,即难以维护
结果是不可移植到其他架构,无论是现有的还是即将出现的
你的代码将仅针对同一架构的特定实现进行优化:例如,在 Intel 兼容平台中,每个 CPU 设计及其变体(处理单元、缓存、RAM、总线、磁盘的相对延迟、吞吐量和容量,FPU、MMX、3DNOW、SIMD 扩展的存在等)都可能意味着完全不同的优化技术。CPU 设计已经包括:Intel 386、486、奔腾、PPro、PII、PIII、PIV;Cyrix 5x86、6x86、M2;AMD K5、K6(K6-2、K6-III)、K7(Athlon、Duron)。新的设计不断涌现,所以不要期望这个列表和你的代码是最新的。
你花费更多时间在一些细节上,而无法专注于大小算法设计,而众所周知,算法设计会带来大部分速度提升(例如,你可能花费一些时间在汇编语言中构建非常快速的列表/数组操作原语;只有哈希表才能更快地加速你的程序;或者,在另一种情况下,二叉树;或者一些分布在 CPU 集群上的高级结构)
算法设计中的一个微小变化可能会完全使你现有的所有汇编代码失效。因此,你要么准备好(并且能够)重写所有代码,要么你被束缚于特定的算法设计
在与标准基准测试相差不远的代码上,商业优化编译器优于手工编码的汇编语言(好吧,这在 x86 架构上不如在 RISC 架构上那么真实,对于广泛可用/免费的编译器来说可能也不太真实;无论如何,对于典型的 C 代码,GCC 相当不错);
无论如何,正如版主 John Levine 在 comp.compilers 上所说,
“编译器使使用复杂数据结构变得容易得多,
而且编译器不会在半途感到厌烦
并且可靠地生成相当不错的代码。”
当在过程和模块边界之间优化代码时,它们还将正确地传播整个(庞大)程序中的代码转换。
总而言之,你可能会发现,尽管有时需要使用汇编语言,甚至在少数情况下即使不需要也可能有用,但你还是会希望
尽量减少汇编代码的使用
将此代码封装在良好定义的接口中
让你的汇编代码从以高于汇编语言的高级语言表达的模式自动生成(例如,GCC 内联汇编宏)
拥有自动工具将这些程序翻译成汇编代码
如果可能,使此代码得到优化
以上所有内容,即编写(对)优化编译器后端(的扩展)。
即使在需要汇编语言时(例如,OS 开发),你也会发现不需要那么多汇编语言,并且上述原则仍然适用。
请参阅关于此的 Linux 内核源代码:尽可能少地使用汇编语言,从而产生快速、可靠、可移植、可维护的操作系统。即使像 DOOM 这样成功的游戏,也几乎完全是用 C 语言编写的,只有很小一部分是用汇编语言编写的,以提高速度。