如何计算跳转目标地址和分支目标地址?
我是汇编语言新手。我正在阅读有关 MIPS 架构的内容,但我对跳转目标地址和分支目标地址指令以及如何计算它们中的每一个指令感到困惑。
I am new to Assembly language. I was reading about the MIPS architecture and I am stuck with the Jump Target Address and Branch Target Address instructions and how to calculate each of them.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
在下面的图表和文本中,
PC
是分支指令本身的地址。PC+4
是分支指令本身的结束,也是下一条指令的开始(MIPS 中使用延迟槽的分支延迟槽)。除了在绝对跳转图中,我们实际上取的是跳转后指令地址的高 4 位。仅在 256 MiB 区域的末尾有所不同。这些图在所谓的 PC 方面彼此不一致,或者可能是通过简化创建的,因为 PC+4 具有与 PC 相同的前 4 位。
1.分支地址计算
在MIPS中,分支指令只有16位偏移量来确定下一条指令。我们需要一个寄存器添加到这个 16 位值来确定下一条指令,这个寄存器实际上是由架构隐含的。它是 PC 寄存器,因为 PC 在取周期期间被更新(PC+4),因此它保存下一条指令的地址。
我们还将分支距离限制为
-2^15 到 +2^15 - 1
指令。然而,这不是真正的问题,因为无论如何大多数分支机构都是本地的。一步一步来:对
2.跳转地址计算
对于跳转指令,MIPS 只有 26 位来确定跳转位置。跳转是相对于 MIPS 中的 PC 而言的。与分支一样,立即跳转值需要字对齐;因此,我们需要将 26 位地址乘以 4。
再次一步一步:
换句话说,将PC+4的低28位替换为所取指令的低26位左移2位。
跳转在包含分支延迟槽的区域内是绝对的,不一定是分支本身。 在上图中,PC 在跳转计算之前已经前进到分支延迟槽。(在经典 RISC 5 级流水线中,BD 在跳转解码的同一周期中获取,因此PC+4 下一个指令地址已经可用于跳转和分支,并且相对于跳转自己的地址进行计算将需要额外的工作来保存该地址。)
来源:比尔肯特大学 CS 224 课程幻灯片
In the diagrams and text below,
PC
is the address of the branch instruction itself.PC+4
is the end of the branch instruction itself, and the start of the next instruction (the branch delay slot in a MIPS that uses delay slots).Except in the absolute jump diagram where we actually take the high 4 bits of the address of the instruction following the jump. That's only different at the end of a 256 MiB region. The diagrams are inconsistent with each other in what they call PC, or perhaps were created with the simplification that PC+4 has the same top 4 bits as PC.
1. Branch Address Calculation
In MIPS branch instruction has only 16 bits offset to determine next instruction. We need a register added to this 16 bit value to determine next instruction and this register is actually implied by architecture. It is PC register since PC gets updated (PC+4) during the fetch cycle so that it holds the address of the next instruction.
We also limit the branch distance to
-2^15 to +2^15 - 1
instructions. However, this is not real issue since most branches are local anyway.So step by step :
2. Jump Address Calculation
For Jump instruction MIPS has only 26 bits to determine Jump location. Jumps are relative to PC in MIPS. Like branch, immediate jump value needs to be word-aligned; therefore, we need to multiply 26 bit address with four.
Again step by step:
In other words, replace the lower 28 bits of the PC + 4 with the lower 26 bits of the fetched instruction shifted left by 2 bits.
Jumps are absolute within the region containing the branch-delay slot, not necessarily the branch itself. In the diagram above, PC has already advanced to the branch delay slot before the jump calculation. (In a classic-RISC 5 stage pipeline, the BD was fetched in the same cycle the jump is decoded, so that PC+4 next instruction address is already available for jumps as well as branches, and calculating relative to the jump's own address would have required extra work to save that address.)
Source: Bilkent University CS 224 Course Slides
通常您不必担心计算它们,因为您的汇编器(或链接器)将进行正确的计算。假设您有一个小函数:
当将上述代码转换为二进制指令流时,汇编器(或链接器,如果您首先组装成目标文件)将确定该函数将驻留在内存中的位置(让我们忽略与位置无关的代码)目前)。它将驻留在内存中的位置通常在 ABI 中指定,或者如果您使用的是模拟器(例如 SPIM 加载
0x400000
- 请注意该链接还包含对该过程的良好解释)。假设我们讨论的是 SPIM 情况,并且我们的函数首先位于内存中,则
slti
指令将驻留在0x400000
处,beq
位于 <代码>0x400004等等。现在我们快到了!对于beq
指令,分支目标地址是cont
(0x400010
)查看MIPS 指令参考 我们看到它被编码为 16 位带符号的直系亲属到下一条指令(除以 4,因为无论如何所有指令都必须驻留在 4 字节对齐的地址上)。即:
beq $t0, $zero, cont
的编码如您所见,您可以分支到
-0x1fffc .. 0x20000
字节内。如果由于某种原因,您需要跳得更远,您可以使用蹦床(无条件跳转到给定限制内的真实目标)。与分支目标地址不同,跳转目标地址是使用绝对地址(再次除以 4)进行编码的。由于指令编码使用 6 位操作码,因此只留下 26 位用于地址(实际上是 28 位,因为最后 2 位将为 0),因此在形成地址时使用 PC 寄存器的 4 位最高有效位(除非您打算跨越 256 MB 边界,否则这并不重要)。
返回到上面的示例,
jal func
的编码是:您可以使用此 在线 MIPS 汇编器 我遇到过(注意它不支持所有操作码,例如
slti
,所以我只是将其更改为slt
这里):Usually you don't have to worry about calculating them as your assembler (or linker) will take of getting the calculations right. Let's say you have a small function:
When translating the above code into a binary stream of instructions the assembler (or linker if you first assembled into an object file) it will be determined where in memory the function will reside (let's ignore position independent code for now). Where in memory it will reside is usually specified in the ABI or given to you if you're using a simulator (like SPIM which loads the code at
0x400000
- note the link also contains a good explanation of the process).Assuming we're talking about the SPIM case and our function is first in memory, the
slti
instruction will reside at0x400000
, thebeq
at0x400004
and so on. Now we're almost there! For thebeq
instruction the branch target address is that ofcont
(0x400010
) looking at a MIPS instruction reference we see that it is encoded as a 16-bit signed immediate relative to the next instruction (divided by 4 as all instructions must reside on a 4-byte aligned address anyway).That is:
Encoding of
beq $t0, $zero, cont
As you can see you can branch to within
-0x1fffc .. 0x20000
bytes. If for some reason, you need to jump further you can use a trampoline (an unconditional jump to the real target placed placed within the given limit).Jump target addresses are, unlike branch target addresses, encoded using the absolute address (again divided by 4). Since the instruction encoding uses 6 bits for the opcode, this only leaves 26 bits for the address (effectively 28 given that the 2 last bits will be 0) therefore the 4 bits most significant bits of the PC register are used when forming the address (won't matter unless you intend to jump across 256 MB boundaries).
Returning to the above example the encoding for
jal func
is:You can quickly verify this, and play around with different instructions, using this online MIPS assembler i ran across (note it doesn't support all opcodes, for example
slti
, so I just changed that toslt
here):我认为计算这些非常困难,因为分支目标地址是在运行时确定的,并且预测是在硬件中完成的。如果您更深入地解释了问题并描述了您正在尝试做的事情,那么会更容易提供帮助。 (:
I think it would be quite hard to calculate those because the branch target address is determined at run time and that prediction is done in hardware. If you explained the problem a bit more in depth and described what you are trying to do it would be a little easier to help. (:
对于像这样的小函数,您可以手动计算从分支指令下的指令到目标的跳数。如果向后分支,则跳数为负。如果该数字不需要全部 16 位,则对于跳数最高有效位左侧的每个数字,将它们设为 1,如果跳数为正,则将它们全部设为 0,因为大多数分支都接近它们目标,这在大多数情况下可以为您节省大量额外的算术。
For small functions like this you could just count by hand how many hops it is to the target, from the instruction under the branch instruction. If it branches backwards make that hop number negative. if that number doesn't require all 16 bits, then for every number to the left of the most significant of your hop number, make them 1's, if the hop number is positive make them all 0's Since most branches are close to they're targets, this saves you a lot of extra arithmetic for most cases.