【发布时间】:2018-03-23 18:52:14
【问题描述】:
当我了解 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
“Save old ra”清楚地表明了保存寄存器的意图,但为什么是 0 美元?
【问题讨论】:
-
这没有明显的意义,但 glibc 是开源的,所以也许检查一下它是从哪里来的?
-
我有,但代码没有解释为什么要写入 $0 而不是其他一些临时寄存器。
-
是glibc中手写的asm吗?有链接吗?
-
如果没有源代码,这可能只是您正在反汇编的数据,就好像它是指令一样。需要确认来源
-
我已将链接和副本添加到问题的来源。