【发布时间】:2018-10-22 20:57:59
【问题描述】:
我将 C 代码转换为 MIPS,但我无法理解 MIPS 指令的一部分:
#include <inttypes.h>
#include <stdint.h>
uint16_t
chksum(uint16_t sum, const uint8_t *data, uint16_t len)
{
uint16_t t;
const uint8_t *dataptr;
const uint8_t *last_byte;
dataptr = data;
last_byte = data + len - 1;
while (dataptr < last_byte)
{
t = (dataptr[0] << 8) + dataptr[1];
sum += t;
if (sum < t)
{
sum++;
}
dataptr += 2;
}
if (dataptr == last_byte)
{
t = (dataptr[0] << 8) + 0;
sum += t;
if (sum < t)
{
sum++;
}
}
return sum;
}
我使用 MIPS gcc5.4 on the Godbolt compiler explorer 和 -O2 优化,经典 MIPS1 的默认 -march 没有负载互锁:
chksum(unsigned short, unsigned char const*, unsigned short):
andi $6,$6,0xffff
addiu $6,$6,-1
addu $6,$5,$6
sltu $3,$5,$6
beq $3,$0,$L2
andi $2,$4,0xffff
move $4,$5
$L4:
lbu $3,0($4)
lbu $7,1($4)
sll $3,$3,8
addu $3,$3,$7
andi $3,$3,0xffff
addu $2,$3,$2
andi $2,$2,0xffff
addiu $4,$4,2
sltu $3,$2,$3
sltu $7,$4,$6
beq $3,$0,$L3
addiu $8,$2,1
andi $2,$8,0xffff
$L3:
bne $7,$0,$L4
nor $3,$0,$5
addu $3,$3,$6
srl $3,$3,1
addiu $3,$3,1
sll $3,$3,1
addu $5,$5,$3
$L2:
beq $6,$5,$L8
nop
$L9:
j $31
nop
$L8:
lbu $3,0($6)
nop
sll $3,$3,8
addu $2,$3,$2
andi $2,$2,0xffff
sltu $3,$2,$3
beq $3,$0,$L9
nop
addiu $2,$2,1
j $31
andi $2,$2,0xffff
我将大部分指令与代码匹配,但我无法理解 $L3 中以 nor 指令开头的部分,直到 addu 之前的 $L2。
编译器资源管理器显示该部分与while 相关,但我不明白为什么它会在$L2 中的分支之前操作$5。
【问题讨论】:
-
t = (dataptr[0] << 8) + dataptr[1];是 16 位大端负载。但不幸的是,编译器没有使用 MIPS 加载半字指令,可能是因为数据可能不是 16 位对齐的。但不幸的是,x86-64 gcc 和 clang 也没有发现它(1 次加载 + 1 次 16 位旋转会比 2 次加载 + 移位 + 便宜):godbolt.org/g/2op8FQ
标签: c assembly compilation mips reverse-engineering