本 LoongArch 指令集研究工作在百度贴吧龙芯吧同步连载。
本研究中涉及的逆向工程仅出于学习、研究目的。本研究工作未得到任何龙芯、麒麟等软硬件厂商的任何形式帮助。
本研究属于个人行为,与本人雇主或任何其他主体无关。
这一回我们接着折腾下面这个函数。
0000000000053368 <PyNode_ListTree>:
53368: 02ff8063 addi sp, sp, -32
5336c: 29c06061
53370: 29c04076
53374: 02c08076 addi r22, sp, 32
53378: 29ffa2c4
5337c: 1c0076ac
53380: 28dab18c
53384: 2600018c
53388: 28ffa2c5
5338c: 00150184
53390: 54001800
53394: 03400000
53398: 28c06061
5339c: 28c04076
533a0: 02c08063 addi sp, sp, 32
533a4: 4c000020 ret
上一回我们提到,在函数头尾经常会有相同数量的 29xxxxxx
和 28xxxxxx
指令出现。这个函数很小,小归小,也有 2 对这玩意……我们就来分析一下。
29c06061 = 0010 1001 1100 0000 0110 0000 0110 0001
= 001010 0111000000011000 00011 00001
= 001010 0111000000011000 sp ra
29c04076 = 0010 1001 1100 0000 0100 0000 0111 0110
= 001010 0111000000010000 00011 10110
= 001010 0111000000010000 sp fp
28c06061 = 0010 1000 1100 0000 0110 0000 0110 0001
= 001010 0011000000011000 00011 00001
= 001010 0011000000000000 sp ra
28c04076 = 0010 1000 1100 0000 0100 0000 0111 0110
= 001010 0011000000010000 00011 10110
= 001010 0011000000010000 sp fp
还是在上一回,我们讲到了进出函数时,要保存、恢复那些被调用方保存的寄存器,保存到哪里呢?当然是栈上咯,也就是基于 sp
的一个偏移量所指向的内存。
那么这几条指令应该就是做这件事情的!
回想一下几个经典的 RISC 指令集的访存指令都怎么安排操作数的,大多数都是 内容寄存器, 偏移量(基址寄存器)
的形式,那么我们有充足的理由相信 LoongArch 也不会例外,在上面找一找哪里是立即数?
没错,至少那一长串的低几位肯定是立即数,那么立即数的边界在哪儿呢?好像从这四条指令看不出边界应该在哪两个 0 之间。
但我们还看到紧接着又有一个 28
开头的指令!
28ffa2c5 = 0010 1000 1111 1111 1010 0010 1100 0101
= 001010 0011111111101000 10110 00101
= 001010 0011111111101000 fp r5
随便找个指令对比,例如 28c04076,可见立即数宽 12 位
28ffa2c5 = 001010 0011 111111101000 fp r5
= 001010 0011 r5, -24(fp)
28c04076 = 001010 0011 000000010000 sp fp
= 001010 0011 fp, 16(sp)
好样的!我们得到 LoongArch 的 64 位访存指令了。“序”与“跋”,分别负责保存和恢复,那么最前面两条肯定是存,最后两条肯定是取。
至于为啥是 64 位,跟之前得到 addi
的逻辑一样:因为这里处理的数据是地址,又是个 64 位应用,显然完整的 64 位都是要保留的。
001010 0111 IMM12 RJ RD => sd rd, imm12(rj) # 将 rd[63..0] 存入 *(rj + imm12) 开始的 8 字节
001010 0011 IMM12 RJ RD => ld rd, imm12(rj) # 从 *(rj + imm12) 读 8 字节存入 rd
我们对这个函数的理解前进了一大步!
0000000000053368 <PyNode_ListTree>:
53368: 02ff8063 addi sp, sp, -32
5336c: 29c06061 sd ra, 24(sp)
53370: 29c04076 sd fp, 16(sp)
53374: 02c08076 addi fp, sp, 32
53378: 29ffa2c4 sd r4, -24(fp)
5337c: 1c0076ac
53380: 28dab18c ld r12, 1708(r12)
53384: 2600018c
53388: 28ffa2c5 ld r5, -24(fp)
5338c: 00150184
53390: 54001800
53394: 03400000
53398: 28c06061 ld ra, 24(sp)
5339c: 28c04076 ld fp, 16(sp)
533a0: 02c08063 addi sp, sp, 32
533a4: 4c000020 ret
那么新的问题来了,r4 r5 r12
都是什么鬼,为啥非要取这么几个序号呢?欲知此事为何,且听下回分解!