可以使用MIPS寄存器$ 0来存储和检索值吗?

时间:2017-10-12 00:05:34

标签: assembly mips glibc

当我了解MIPS处理器时,我的脑海里一直认为$ 0寄存器的读取总是返回0,并且写入$ 0总是被丢弃。来自MIPS程序员手册:

  

2.13.4.1 CPU通用寄存器   [...]   r0硬连接到值   零,可以用作任何指令的目标寄存器   结果将被丢弃。当零为零时,r0也可以用作源   价值是必要的。

由此可见,or $0,$r31,$0指令是无操作的。

当我在ELF MIPS二进制文件的启动代码中查看时,想象一下,当我看到以下指令序列时,我感到惊讶:

00000610 03 E0 00 25   or     $0,$ra,$0
00000614 04 11 00 01   bgezal $0,0000061C
00000618 00 00 00 00   nop
0000061C 3C 1C 00 02   lui    $28,+0002
00000620 27 9C 84 64   addiu  $28,$28,-00007B9C
00000624 03 9F E0 21   addu   $28,$28,$ra
00000628 00 00 F8 25   or     $ra,$0,$0

地址0x610处的指令是将$ ra的值复制到$ r0,根据上面的段落等于丢弃它。然后,地址0x628处的指令从$ 0读回值,但由于$ 0硬连线为0,因此将$ ra设置为0.

这一切似乎都毫无意义:为什么只执行0x628就执行语句0x610。 glibc人员在编写此代码时显然有一些意图。似乎$ 0毕竟是可写的和可读的!

那么在什么情况下程序可以读/写$ 0寄存器,好像它是任何一个其他通用寄存器一样?

编辑: 查看glibc源代码并不是很有用。 __start的代码 使用宏:

https://github.com/bminor/glibc/blob/master/sysdeps/mips/start.S#L80

ENTRY_POINT:
# ifdef __PIC__
    SETUP_GPX($0)
...

注意这里有意指定$ 0。 SETUP_GPX宏在此处定义:

https://github.com/bminor/glibc/blob/master/sysdeps/mips/sys/asm.h#L75

# define SETUP_GPX(r)                           \
        .set noreorder;                         \
        move r, $31;     /* Save old ra.  */     \
        bal 10f; /* Find addr of cpload.  */    \
        nop;                                    \
10:                                             \
        .cpload $31;                             \
        move $31, r;                             \
        .set reorder

"保存旧的"明确表示保存寄存器的意图,但为什么是$ 0?

2 个答案:

答案 0 :(得分:4)

它使用$0因为在入口点没有理由保存$ra,所以它只是被丢弃了。由于它手写的asm代码来自一个宏,因此它没有像通常情况那样进行优化。

答案 1 :(得分:1)

请注意,glibc仅将此用于PIC。 (见Is all MIPS code on Linux supposed to be PIC?

MIPS jal(与其他j指令一样)不是PIC;它用imm26 << 2取代了低28位的PC。 It's an absolute call within that 1/16th of address space

但是b指令编码确实使用相对位移,所以它仍然有效。 bal是无条件PIC函数调用的伪指令:它设置PC += imm16<<2(参见同一链接)。它是针对$0测试>= 0的条件分支链接的伪指令,所以它总是被采用。正如您的反汇编所示,真正的指令是"BGEZAL -- Branch on greater than or equal to zero and link"。它只能在-2 ^ 17 / +(2 ^ 17 - 4)字节内工作。

&#34;和链接&#34;部分是这段代码所需要的:它通过使用分支链接将PC变为$ra,因为在PIC中,您在汇编或链接时不知道自己的地址。

无论如何,这解释了为什么bgezal $0正在阅读$0 。通过特殊设置这个宏的使用,他们可以通过将旧值无用的写入$0来保存每个可执行文件至少4个字节。但是他们并没有:/代码只运行一次。