考虑以下MIPS程序集(我使用MIPS是因为我的《计算机组织与设计》一书使用了MIPS):
beq $s0, $s1, L1
add $t0, $t1, $t2
...
L1: ...
因为MIPS在beq
指令中只使用16位作为PC相对地址,所以如果L1
离beq
足够远,汇编程序必须用两条指令(一个跳跃有26位作为地址)和一个新标签来替换它:
bne $s0, $s1, L2
j L1
L2: add $t0, $t1, $t2
...
L1: ...
如果这还不够,它可能需要多次跳跃。
在知道L1
的位置之前,汇编程序不知道是否需要进行此替换。由于它最初不知道beq
(1指令或2指令)的大小,因此如何在第一次通过时保持位置计数器的最新状态?
有多种方法:
- 只为一条指令保留空间,如果发现空间不够,请展开它
- 为两条指令保留足够的空间,然后用
nop
(s)填充未使用的空间或压缩代码
无论哪种情况,您都不必立即生成(半)最终机器代码,也不需要重新扫描源代码并重新组装,尽管这是可能的。您可以首先生成"中间"代码或其表示,然后修复它,就像链接器所做的那样。
说到哪个[链接器],还有另一个选择:
- 将此片段留给链接器处理。这不是很难。如今,编译器(例如Microsoft Visual C++)可以进行链接时代码优化