链接器如何重新定位 MIPS 中的分支指令?
How does a linker relocate branch instructions in MIPS?
背景
我正在研究 2015 CS61C(伯克利)课程项目,将 linker 写入从以下 MIPS 指令集子集生成的 link 目标文件。
Add Unsigned: addu $rd, $rs, $rt
Or: or $rd, $rs, $rt
Set Less Than: slt $rd, $rs, $rt
Set Less Than Unsigned: sltu $rd, $rs, $rt
Jump Register: jr $rs
Shift Left Logical: sll $rd, $rt, shamt
Add Immediate Unsigned: addiu $rt, $rs, immediate
Or Immediate: ori $rt, $rs, immediate
Load Upper Immediate: lui $rt, immediate
Load Byte: lb $rt, offset($rs)
Load Byte Unsigned: lbu $rt, offset($rs)
Load Word: lw $rt, offset($rs)
Store Byte: sb $rt, offset($rs)
Store Word: sw $rt, offset($rs)
Branch on Equal: beq $rs, $rt, label
Branch on Not Equal: bne $rs, $rt, label
Jump: j label
Jump and Link: jal label
Load Immediate: li $rt, immediate
Branch on Less Than: blt $rs, $rt, label
从这个指令子集来看,我认为需要重定位的是j
、bne
、beq
指令(blt
是伪指令),如果标签不在同一个文件中,则后两者需要重新定位。
执行指令重定位的 MIPS 函数的注释读取
#------------------------------------------------------------------------------
# function relocate_inst()
#------------------------------------------------------------------------------
# Given an instruction that needs relocation, relocates the instruction based
# on the given symbol and relocation table.
#
# You should return error if 1) the addr is not in the relocation table or
# 2) the symbol name is not in the symbol table. You may assume otherwise the
# relocation will happen successfully.
#
# Arguments:
# $a0 = an instruction that needs relocating
# $a1 = the byte offset of the instruction in the current file
# $a2 = the symbol table
# $a3 = the relocation table
#
# Returns: the relocated instruction, or -1 if error
请注意,重定位 table 包含相对于正在 linked 的目标文件开头的地址,而符号 table 是符号 [=53= 的集合]s 的所有目标文件被 linked 并包含绝对地址。
问题
如果要重定位的指令是j
指令,由于$a1
包含指令的相对地址,我们在重定位 table,然后在符号 table 中找到该标签的绝对地址。我们可以将(绝对地址 >> 2)添加为指令的低 26 位。
如果要重定位的指令是 bne
,或者 beq
但是,我不知道该怎么做,因为低位应该是相对于PC+4,但是我们不知道被重定位的指令的绝对地址是多少,所以我们不知道PC+4是什么。
网上看了各种solutions,好像只处理了j
个搬迁
我是不是漏掉了什么?
编辑:我们只考虑文本段。
我的猜测是这个链接器不处理到外部标签的分支指令(bne
或 beq
)。
这将阻止使用 beq label
标签是外部的(全局的和在另一个目标文件中),但这只能在汇编中真正做到。
例如,编译器输出会将分支指令和目标位置都放在一个函数中,该函数进入一个代码块。 (取模某些尾调用优化)。
有了这个限制,那么所有 bne
和 beq
指令都已经由编译器或汇编程序使用 pc-relative 寻址修复了——不需要在这些的搬迁 table。
此外,分支 (beq
/bne
) 指令的范围 (+/-128k) 比 j
短,所以如果链接器真的打算支持分支到外部标签,它可能还必须提供引入分支岛的能力来处理分支太远的那些。
扩展您的示例:
if ( a1 == a0 )
printf ("hello")
会是
bne a1, a0, endIf1
la a0, Lhello
jal printf
endIf1:
一些编译器不知道哪个函数在哪个 DLL 中,因此,即使 printf
在 DLL 中,编译器输出看起来仍然相同。
背景
我正在研究 2015 CS61C(伯克利)课程项目,将 linker 写入从以下 MIPS 指令集子集生成的 link 目标文件。
Add Unsigned: addu $rd, $rs, $rt
Or: or $rd, $rs, $rt
Set Less Than: slt $rd, $rs, $rt
Set Less Than Unsigned: sltu $rd, $rs, $rt
Jump Register: jr $rs
Shift Left Logical: sll $rd, $rt, shamt
Add Immediate Unsigned: addiu $rt, $rs, immediate
Or Immediate: ori $rt, $rs, immediate
Load Upper Immediate: lui $rt, immediate
Load Byte: lb $rt, offset($rs)
Load Byte Unsigned: lbu $rt, offset($rs)
Load Word: lw $rt, offset($rs)
Store Byte: sb $rt, offset($rs)
Store Word: sw $rt, offset($rs)
Branch on Equal: beq $rs, $rt, label
Branch on Not Equal: bne $rs, $rt, label
Jump: j label
Jump and Link: jal label
Load Immediate: li $rt, immediate
Branch on Less Than: blt $rs, $rt, label
从这个指令子集来看,我认为需要重定位的是j
、bne
、beq
指令(blt
是伪指令),如果标签不在同一个文件中,则后两者需要重新定位。
执行指令重定位的 MIPS 函数的注释读取
#------------------------------------------------------------------------------
# function relocate_inst()
#------------------------------------------------------------------------------
# Given an instruction that needs relocation, relocates the instruction based
# on the given symbol and relocation table.
#
# You should return error if 1) the addr is not in the relocation table or
# 2) the symbol name is not in the symbol table. You may assume otherwise the
# relocation will happen successfully.
#
# Arguments:
# $a0 = an instruction that needs relocating
# $a1 = the byte offset of the instruction in the current file
# $a2 = the symbol table
# $a3 = the relocation table
#
# Returns: the relocated instruction, or -1 if error
请注意,重定位 table 包含相对于正在 linked 的目标文件开头的地址,而符号 table 是符号 [=53= 的集合]s 的所有目标文件被 linked 并包含绝对地址。
问题
如果要重定位的指令是
j
指令,由于$a1
包含指令的相对地址,我们在重定位 table,然后在符号 table 中找到该标签的绝对地址。我们可以将(绝对地址 >> 2)添加为指令的低 26 位。如果要重定位的指令是
bne
,或者beq
但是,我不知道该怎么做,因为低位应该是相对于PC+4,但是我们不知道被重定位的指令的绝对地址是多少,所以我们不知道PC+4是什么。
网上看了各种solutions,好像只处理了j
个搬迁
我是不是漏掉了什么?
编辑:我们只考虑文本段。
我的猜测是这个链接器不处理到外部标签的分支指令(bne
或 beq
)。
这将阻止使用 beq label
标签是外部的(全局的和在另一个目标文件中),但这只能在汇编中真正做到。
例如,编译器输出会将分支指令和目标位置都放在一个函数中,该函数进入一个代码块。 (取模某些尾调用优化)。
有了这个限制,那么所有 bne
和 beq
指令都已经由编译器或汇编程序使用 pc-relative 寻址修复了——不需要在这些的搬迁 table。
此外,分支 (beq
/bne
) 指令的范围 (+/-128k) 比 j
短,所以如果链接器真的打算支持分支到外部标签,它可能还必须提供引入分支岛的能力来处理分支太远的那些。
扩展您的示例:
if ( a1 == a0 )
printf ("hello")
会是
bne a1, a0, endIf1
la a0, Lhello
jal printf
endIf1:
一些编译器不知道哪个函数在哪个 DLL 中,因此,即使 printf
在 DLL 中,编译器输出看起来仍然相同。