是的,你的假设是正确的。有多种类型的重定位,汇编器发出到指令中的内容取决于类型。通常它是要添加的偏移量。您可以使用objdump -dr
查看重定位。为了更好地说明,我稍微更改了您的代码:
.data
.int 0
TEXT: .asciiz "Foo"
.text
.global main
main:
li $t0, 1
beq $t0, 1, equal #B
bne $t0, 42, foo #C
equal:
la $a0, TEXT
jal printf #A
objdump 的输出:
00000000 <main>:
0: 24080001 li t0,1
4: 24010001 li at,1
8: 11010004 beq t0,at,1c <equal>
c: 00000000 nop
10: 2401002a li at,42
14: 1501ffff bne t0,at,14 <main+0x14>
14: R_MIPS_PC16 foo
18: 00000000 nop
0000001c <equal>:
1c: 3c040000 lui a0,0x0
1c: R_MIPS_HI16 .data
20: 0c000000 jal 0 <main>
20: R_MIPS_26 printf
24: 24840004 addiu a0,a0,4
24: R_MIPS_LO16 .data
正如您所说,没有重定位,beq
因为这是该目标文件中的相对地址。
bne
我添加的(标有 的行C
)引用了一个外部符号,因此即使地址是相对的,也需要重定位条目。它将是R_MIPS_PC16
产生符号的 16 位有符号字偏移的类型foo
。由于指令编码需要从下一个字偏移而不是PC
重定位使用的当前字,1
因此必须减去,并将其编码为ffff
指令本身的 2 的补码。
la
伪指令已由汇编器翻译成/lui
对addiu
(后者在 的延迟槽中jal
)。对于将填充前 16 位的部分lui
创建R_MIPS_HI16
重定位。.data
由于符号位于段TEXT
中的地址处,因此偏移量的前 16 位为. 这意味着指令包含偏移量。类似地,对于低 16 位,除了该指令包含的偏移量为.4
.data
0
0
4
最后,jal printf
正在使用另一种为指令所需的编码量身定制的重定位。偏移量为零,因为跳转直接到引用的符号。请注意,objdump 试图通过解码来提供帮助,但它不处理重定位,因此<main>
它输出的当然是无稽之谈。