assembly - MIPS 跳转和分支指令范围

标签 assembly mips machine-code

我刚开始学习 MIPS,但在理解跳转和分支指令的范围时遇到了麻烦。我知道 PC 可以跳跃和分支的“远”有多远是有限制的,但我不明白为什么。

还有2个具体问题,如果当前值PC0x00000000 ,是否可以对随机地址执行 1 JUMP?如果 PC 的当前值是 0x00000600 ,是否可以对随机地址执行 1 BRANCH?

最佳答案

MIPS 处理器使用固定大小的指令,其中每个指令字都是一个字(即 4 字节 == 32 位)。所以只有这么多信息可以塞进这 4 个字节中。
JJAL指令使用 32 位中的 6 位来指定操作码。这留下了 26 位来指定目标地址。尽管没有直接在指令中指定目标地址(没有足够的位) - 相反,会发生以下情况:

  • 将目标地址的低 28 位右移 2 位,然后将最低 26 位存储在指令字中。由于所有指令都必须字对齐,因此我们移出的两位将始终为零,因此我们不会丢失任何无法重新创建的信息。
  • 当跳转发生时,这26位左移2位得到原来的28位,然后与J后面的指令地址的4个最高有效位结合起来。/JAL形成一个 32 位地址。

  • 这使得可以跳转到跳转指令所在的相同 256MB 范围 (2^28) 中的任何指令(或者如果启用了延迟分支;跳转到与延迟中的指令相同的 256MB 范围内的任何指令)投币口)。

    对于分支指令,有 16 位可用于指定目标地址。这些存储为相对于分支指令之后的指令的有符号偏移量(再次应用两位移位,因为没有必要存储我们知道始终为 0 的东西)。所以恢复2个最低有效位后的实际偏移量为18位,然后将其符号扩展为32位并添加到分支指令之后的指令地址。这使得可以在分支指令内分支到 +/-128kB。

    考虑在地址 0x00400024 加载的以下代码:
    main:
    j foo
    nop
    foo:
    b main
    nop
    
    j foo指令编码为 0x0810000b . 26 个最低有效位的值为 0x10000b , 左移 2 位后变成 0x40002c . j后面的指令地址的4个最高有效位为零,所以目标地址变为 (0 << 28) | 0x40002c , 等于 0x40002c ,恰好是foo的地址.
    b main指令编码为 0x0401fffd . 16 个最低有效位的值为 0xfffd , 左移 2 位后变为 0x3fff4 .将其符号扩展到 32 位给我们 0xfffffff4 .并将其添加到 b 之后的指令地址时我们得到 0x400030 + 0xfffffff4 ,其中(当截断为 32 位时)等于 0x400024 ,恰好是main的地址.

    如果要跳转到某个任意地址,请将地址加载到寄存器中并使用 jrjalr指令跳跃。

    关于assembly - MIPS 跳转和分支指令范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36442586/

    相关文章:

    gcc - 无法编译程序集 :/usr/bin/ld: i386 architecture of input file `array1.o' is incompatible with i386:x86-64 output

    assembly - 将数组初始化为程序集中的特定值 (x86)

    c - 地址和推送指令前的星号,它被推送到哪里?

    assembly - 计算mips汇编控制指令的目标地址

    c - 如何强制 GAS 生成与输入相同的输出?

    c - gcc内联汇编错误

    c - 如何在没有main的情况下运行MIPS程序并从C程序调用MIPS程序

    assembly - 我应该如何使用英特尔的文档获取与 x86 中的 `ModeR/M` 指令相对应的 `call dword ptr` 字节?

    assembly - 字节码和汇编语言是一回事吗?

    compiler-construction - 编译为机器代码的编译器是否需要用汇编编写?