我试图了解R_MIPS_HI16和R_MIPS_LO16在mips中是如何工作的。
我编写了一些c代码:
static char buf1[0x100];
static int a = 0;
static int b = 0;
char f(int i, int n)
{
a++;
b++;
return buf1[n];
}
用mips-linux-gnu-gcc-8 -o test.o -c -O2 -G 0 -g test.c
编译并运行objdump:mips-linux-gnu-objdump -d -j .text test.o
我得到以下信息:
00000030 <f>:
30: 3c070000 lui a3,0x0
34: 3c060000 lui a2,0x0
38: 3c020000 lui v0,0x0
3c: 8ce50004 lw a1,4(a3)
40: 8cc30000 lw v1,0(a2)
44: 24420008 addiu v0,v0,8
48: 00442021 addu a0,v0,a0
4c: 24a50001 addiu a1,a1,1
50: 24630001 addiu v1,v1,1
54: 80820000 lb v0,0(a0)
58: ace50004 sw a1,4(a3)
5c: 03e00008 jr ra
60: acc30000 sw v1,0(a2)
现在我运行mips-linux-gnu-readelf -r test.o
以获得重新定位表:
Relocation section '.rel.text' at offset 0x79c contains 12 entries:
Offset Info Type Sym.Value Sym. Name
00000008 00000405 R_MIPS_HI16 00000000 .bss
00000018 00000406 R_MIPS_LO16 00000000 .bss
00000014 00000405 R_MIPS_HI16 00000000 .bss
0000001c 00000406 R_MIPS_LO16 00000000 .bss
00000030 00000405 R_MIPS_HI16 00000000 .bss
0000003c 00000406 R_MIPS_LO16 00000000 .bss
00000040 00000406 R_MIPS_LO16 00000000 .bss
00000038 00000405 R_MIPS_HI16 00000000 .bss
00000044 00000406 R_MIPS_LO16 00000000 .bss
00000058 00000406 R_MIPS_LO16 00000000 .bss
00000034 00000405 R_MIPS_HI16 00000000 .bss
00000060 00000406 R_MIPS_LO16 00000000 .bss
现在,根据ABI第4-17节,每个R_MIPS_HI16重新定位都有一个匹配的R_MIPS_LO16.如果前面有一个没有R_MIPS_LO16的R_MIPS_HI16,它将引用之前的R_MIPS_HI16。
如果我理解得对,这就意味着38和44的重新定位是成对的。在地址38中,我们将地址的较高部分移动到寄存器(v0),在44中,我们添加到相同的寄存器中,以完成地址的加载。
我不明白的是,58中的重新定位也耦合到同一个R_MIPS_HI16,但在这个地址中,我们没有访问以前命令中使用的任何寄存器,它们似乎也没有关联。实际上,这个命令似乎与对30和3c相关。
这里发生什么事情?
发布于 2020-03-22 07:02:20
您正在观察a++
和b++
的优化。
虽然人们可能认为b = b + 1
包含一个b
负载和一个b
存储,需要lui/lw
对来读取b
和lui/sw
对来写入b
,但是编译器知道,对b
的读取和b
的写入都需要相同的lui
,因此它消除了第二个lui
,重用了第一个lui
的目标寄存器--因此它正在执行lui/lw/sw
。
如果你是手动写这个的话,还有一个小程序。对于所有的全局变量,您可以使用/共享一个lui
。
但是由于这些变量被分配给.bss
(它们都是零初始化的),链接器决定它们的最终位置(尽管它们在源程序中一起声明,但它们是单独的项),所以我们实际上不知道它们在编译时的距离有多近。
此外,由于这是一个程序片段,我们也不知道程序总共将有多少个全局值,因此,在任意两个全局之间可能会出现64k的边界,这意味着这两个全局将需要不同的lui
。
由于最终的确定是由链接器完成的,编译器在这里假设最坏的情况,并对每个全局变量使用一个单独的lui
。
经过一番讨论..。
我明白你的意思了。我告诉你们的是,30,3c和58与变量的相同访问有关,这是正确的。搬迁,我不熟悉,但你可能会发现这相关:
https://github.com/NationalSecurityAgency/ghidra/issues/909
虽然我理解解释ABI的方式,但HI16不影响LO16重新定位修复,但是我们目前的实现只有影响HI16修复的LO16,因为在HI16计算过程中可能会进入前16位。
底线是,虽然HI16需要与LO16配对才能计算进位,但如果没有前面的HI16,则以前配对的LO16的重复是可以的,因为已经完成了进入HI16的适当进位--因此HI16/LO16的重新定位并不是真正的配对1:1。
https://stackoverflow.com/questions/60800531
复制相似问题