Skip to content

Commit 7bcd5aa

Browse files
committed
WIP [mips] Fixing PR for r5900: merged from dev, integrate MIPS version awareness, fix 3-op variants of MULT/U and MADD/U, WIP tweaking register size on R5900
1 parent 9f38795 commit 7bcd5aa

File tree

6 files changed

+107
-19
lines changed

6 files changed

+107
-19
lines changed

arch/mips/arch_mips.cpp

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -534,7 +534,7 @@ class MipsArchitecture: public Architecture
534534
il.AddInstruction(il.If(GetConditionForInstruction(il, instr, GetAddressSize()), trueCode, falseCode));
535535
il.MarkLabel(trueCode);
536536
il.SetCurrentAddress(this, addr + instr.size);
537-
GetLowLevelILForInstruction(this, addr + instr.size, il, secondInstr, GetAddressSize(), m_decomposeFlags);
537+
GetLowLevelILForInstruction(this, addr + instr.size, il, secondInstr, GetAddressSize(), m_decomposeFlags, m_version);
538538
for (size_t i = 0; i < instrInfo.branchCount; i++)
539539
{
540540
if (instrInfo.branchType[i] == TrueBranch)
@@ -560,7 +560,7 @@ class MipsArchitecture: public Architecture
560560
nop = il.Nop();
561561
il.AddInstruction(nop);
562562

563-
GetLowLevelILForInstruction(this, addr + instr.size, il, secondInstr, GetAddressSize(), m_decomposeFlags);
563+
GetLowLevelILForInstruction(this, addr + instr.size, il, secondInstr, GetAddressSize(), m_decomposeFlags, m_version);
564564

565565
LowLevelILInstruction delayed;
566566
uint32_t clobbered = BN_INVALID_REGISTER;
@@ -587,7 +587,7 @@ class MipsArchitecture: public Architecture
587587
}
588588
else
589589
{
590-
status = GetLowLevelILForInstruction(this, addr, il, instr, GetAddressSize(), m_decomposeFlags);
590+
status = GetLowLevelILForInstruction(this, addr, il, instr, GetAddressSize(), m_decomposeFlags, m_version);
591591
}
592592

593593
if (clobbered != BN_INVALID_REGISTER)
@@ -752,12 +752,12 @@ class MipsArchitecture: public Architecture
752752
else
753753
base->operation = is32bit ? MIPS_LW : MIPS_LD;
754754

755-
return GetLowLevelILForInstruction(this, addrToUse, il, *base, GetAddressSize(), m_decomposeFlags);
755+
return GetLowLevelILForInstruction(this, addrToUse, il, *base, GetAddressSize(), m_decomposeFlags, m_version);
756756
}
757757
}
758758

759759
len = instr.size;
760-
return GetLowLevelILForInstruction(this, addr, il, instr, GetAddressSize(), m_decomposeFlags);
760+
return GetLowLevelILForInstruction(this, addr, il, instr, GetAddressSize(), m_decomposeFlags, m_version);
761761
}
762762

763763
virtual bool GetInstructionInfo(const uint8_t* data, uint64_t addr, size_t maxLen, InstructionInfo& result) override
@@ -1570,7 +1570,12 @@ class MipsArchitecture: public Architecture
15701570
REG_DESAVE,
15711571
};
15721572

1573-
if ((m_decomposeFlags & DECOMPOSE_FLAGS_CAVIUM) != 0)
1573+
if (m_version == MIPS_R5900) {
1574+
// TODO: R5900 has 128-bit wide GPRs, $lo and $hi are 128-bit, and $lo1 and $hi1 are the upper 64 bits of $lo and $hi
1575+
uint32_t r5900_registers[] = { REG_LO1, REG_HI1 };
1576+
registers.insert(registers.end(), std::begin(r5900_registers), std::end(r5900_registers));
1577+
}
1578+
else if ((m_decomposeFlags & DECOMPOSE_FLAGS_CAVIUM) != 0)
15741579
{
15751580
uint32_t cavium_registers[] =
15761581
{
@@ -1888,7 +1893,11 @@ class MipsArchitecture: public Architecture
18881893
REG_DESAVE,
18891894
};
18901895

1891-
if ((m_decomposeFlags & DECOMPOSE_FLAGS_CAVIUM) != 0)
1896+
if (m_version == MIPS_R5900) {
1897+
uint32_t r5900_registers[] = { REG_LO1, REG_HI1 };
1898+
registers.insert(registers.end(), std::begin(r5900_registers), std::end(r5900_registers));
1899+
}
1900+
else if ((m_decomposeFlags & DECOMPOSE_FLAGS_CAVIUM) != 0)
18921901
{
18931902
uint32_t cavium_registers[] =
18941903
{
@@ -2098,6 +2107,18 @@ class MipsArchitecture: public Architecture
20982107
virtual BNRegisterInfo GetRegisterInfo(uint32_t reg) override
20992108
{
21002109
BNRegisterInfo result = {reg, 0, m_bits / 8, NoExtend};
2110+
if (m_version == MIPS_R5900) {
2111+
switch (reg) {
2112+
case REG_LO:
2113+
case REG_HI:
2114+
case REG_LO1:
2115+
case REG_HI1:
2116+
result.size = 64 / 8;
2117+
default:
2118+
if (REG_ZERO <= reg && reg <= REG_RA)
2119+
result.size = 128 / 8;
2120+
}
2121+
}
21012122
return result;
21022123
}
21032124

arch/mips/il.cpp

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -796,7 +796,7 @@ static void SignExtendHiLo(LowLevelILFunction& il, size_t registerSize)
796796
}
797797
}
798798

799-
bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFunction& il, Instruction& instr, size_t addrSize, uint32_t decomposeFlags)
799+
bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFunction& il, Instruction& instr, size_t addrSize, uint32_t decomposeFlags, MipsVersion version)
800800
{
801801
LowLevelILLabel trueLabel, falseLabel, doneLabel, dirFlagSet, dirFlagClear, dirFlagDone;
802802
InstructionOperand& op1 = instr.operands[0];
@@ -1179,15 +1179,61 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu
11791179
SignExtendHiLo(il, registerSize);
11801180
break;
11811181
case MIPS_MULT:
1182-
il.AddInstruction(il.SetRegisterSplit(4, REG_HI, REG_LO, il.MultDoublePrecSigned(4, ReadILOperand(il, instr, 1, registerSize), ReadILOperand(il, instr, 2, registerSize))));
1183-
SignExtendHiLo(il, registerSize);
1184-
if (rd != REG_ZERO)
1185-
// mflo
1186-
il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, rd, il.Register(registerSize, REG_LO)));
1182+
if (version == MIPS_R5900 && instr.numOperands == 3) {
1183+
auto temp = LLIL_TEMP(0);
1184+
il.AddInstruction(il.SetRegister(8, temp,
1185+
il.MultDoublePrecSigned(4,
1186+
ReadILOperand(il, instr, 2, registerSize),
1187+
ReadILOperand(il, instr, 3, registerSize))));
1188+
il.AddInstruction(il.SetRegister(registerSize, REG_HI, il.SignExtend(8, il.ArithShiftRight(8, il.Register(8, temp), il.Const(8, 32)))));
1189+
il.AddInstruction(il.SetRegister(registerSize, REG_LO, il.SignExtend(8, il.LowPart(4, il.Register(8, temp)))));
1190+
// il.AddInstruction(il.SetRegisterSplit(4, REG_HI, REG_LO,
1191+
// il.MultDoublePrecSigned(8,
1192+
// ReadILOperand(il, instr, 2, registerSize),
1193+
// ReadILOperand(il, instr, 3, registerSize))));
1194+
SignExtendHiLo(il, registerSize);
1195+
auto rd = op1.reg;
1196+
if (rd != REG_ZERO)
1197+
il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, rd, il.Register(registerSize, REG_LO)));
1198+
}
1199+
// if (version == MIPS_R5900 && instr.numOperands == 3) {
1200+
// il.AddInstruction(il.SetRegisterSplit(4, REG_HI, REG_LO,
1201+
// il.MultDoublePrecSigned(8,
1202+
// ReadILOperand(il, instr, 2, registerSize),
1203+
// ReadILOperand(il, instr, 3, registerSize))));
1204+
// SignExtendHiLo(il, registerSize);
1205+
// auto rd = op1.reg;
1206+
// if (rd != REG_ZERO)
1207+
// il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, rd, il.Register(registerSize, REG_LO)));
1208+
// }
1209+
else
1210+
{
1211+
il.AddInstruction(il.SetRegisterSplit(4, REG_HI, REG_LO,
1212+
il.MultDoublePrecSigned(4,
1213+
ReadILOperand(il, instr, 1, registerSize),
1214+
ReadILOperand(il, instr, 2, registerSize))));
1215+
SignExtendHiLo(il, registerSize);
1216+
}
11871217
break;
11881218
case MIPS_MULTU:
1189-
il.AddInstruction(il.SetRegisterSplit(4, REG_HI, REG_LO, il.MultDoublePrecUnsigned(4, ReadILOperand(il, instr, 1, registerSize), ReadILOperand(il, instr, 2, registerSize))));
1190-
SignExtendHiLo(il, registerSize);
1219+
if (version == MIPS_R5900 && instr.numOperands == 3) {
1220+
il.AddInstruction(il.SetRegisterSplit(4, REG_HI, REG_LO,
1221+
il.MultDoublePrecUnsigned(4,
1222+
ReadILOperand(il, instr, 2, registerSize),
1223+
ReadILOperand(il, instr, 3, registerSize))));
1224+
SignExtendHiLo(il, registerSize);
1225+
auto rd = op1.reg;
1226+
if (rd != REG_ZERO)
1227+
il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, rd, il.Register(registerSize, REG_LO)));
1228+
}
1229+
else
1230+
{
1231+
il.AddInstruction(il.SetRegisterSplit(4, REG_HI, REG_LO,
1232+
il.MultDoublePrecUnsigned(4,
1233+
ReadILOperand(il, instr, 1, registerSize),
1234+
ReadILOperand(il, instr, 2, registerSize))));
1235+
SignExtendHiLo(il, registerSize);
1236+
}
11911237
break;
11921238
case MIPS_DMULT:
11931239
il.AddInstruction(il.SetRegisterSplit(8, REG_HI, REG_LO, il.MultDoublePrecSigned(8, ReadILOperand(il, instr, 1, registerSize), ReadILOperand(il, instr, 2, registerSize))));

arch/mips/il.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ bool GetLowLevelILForInstruction(
8888
BinaryNinja::LowLevelILFunction& il,
8989
mips::Instruction& instr,
9090
size_t addrSize,
91-
uint32_t decomposeFlags);
91+
uint32_t decomposeFlags,
92+
mips::MipsVersion version);
9293

9394
BinaryNinja::ExprId GetConditionForInstruction(BinaryNinja::LowLevelILFunction& il, mips::Instruction& instr, size_t registerSize);

arch/mips/mips/mips.c

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ using namespace mips;
2222
do { \
2323
instruction->operands[0].operandClass = A;\
2424
instruction->operands[0].VAR(A) = a;\
25+
instruction->numOperands = 1;\
2526
} while (0);
2627

2728
#define INS_2(A,a,B,b)\
@@ -30,6 +31,7 @@ using namespace mips;
3031
instruction->operands[0].VAR(A) = a;\
3132
instruction->operands[1].operandClass = B;\
3233
instruction->operands[1].VAR(B) = b;\
34+
instruction->numOperands = 2;\
3335
} while (0);
3436

3537
#define INS_3(A,a,B,b,C,c)\
@@ -40,6 +42,7 @@ using namespace mips;
4042
instruction->operands[1].VAR(B) = b;\
4143
instruction->operands[2].operandClass = C;\
4244
instruction->operands[2].VAR(C) = c;\
45+
instruction->numOperands = 3;\
4346
} while (0);
4447

4548
#define INS_4(A,a,B,b,C,c,D,d)\
@@ -52,6 +55,7 @@ using namespace mips;
5255
instruction->operands[2].VAR(C) = c;\
5356
instruction->operands[3].operandClass = D;\
5457
instruction->operands[3].VAR(D) = d;\
58+
instruction->numOperands = 4;\
5559
} while (0);
5660

5761

@@ -126,7 +130,7 @@ static Operation mips_base_table[7][8][8] = {
126130
{MIPS_INVALID, MIPS_INVALID, MIPS_J, MIPS_JAL, MIPS_BEQ, MIPS_BNE, MIPS_BLEZ, MIPS_BGTZ},
127131
{MIPS_ADDI, MIPS_ADDIU, MIPS_SLTI, MIPS_SLTIU, MIPS_ANDI, MIPS_ORI, MIPS_XORI, MIPS_LUI},
128132
{MIPS_COP0, MIPS_COP1, MIPS_COP2, MIPS_INVALID, MIPS_BEQL, MIPS_BNEL, MIPS_BLEZL, MIPS_BGTZL},
129-
{MIPS_DADDI, MIPS_DADDIU, MIPS_LDL, MIPS_LDR, MIPS_INVALID, MIPS_INVALID, MIPS_LQ, MIPS_SQ},
133+
{MIPS_DADDI, MIPS_DADDIU, MIPS_LDL, MIPS_LDR, MIPS_INVALID, MIPS_INVALID, MIPS_LQ, MIPS_SQ},
130134
{MIPS_LB, MIPS_LH, MIPS_LWL, MIPS_LW, MIPS_LBU, MIPS_LHU, MIPS_LWR, MIPS_LWU},
131135
{MIPS_SB, MIPS_SH, MIPS_SWL, MIPS_SW, MIPS_SDL, MIPS_SDR, MIPS_SWR, MIPS_CACHE},
132136
{MIPS_INVALID, MIPS_LWC1, MIPS_INVALID, MIPS_PREF, MIPS_INVALID, MIPS_INVALID, MIPS_LDC2, MIPS_LD},
@@ -1509,7 +1513,10 @@ static const char * const RegisterStrings[] = {
15091513
"CVMX_HSH_STARTSHA512",
15101514
"CVMX_GFM_XORMUL1",
15111515

1512-
"sa"
1516+
"sa",
1517+
1518+
"$lo1",
1519+
"$hi1",
15131520
};
15141521

15151522
static const char * const FlagStrings[] = {
@@ -1657,6 +1664,8 @@ uint32_t mips_decompose_instruction(
16571664
instruction->operation = mips32_special3_table[ins.decode.func_hi][ins.decode.func_lo];
16581665
else if (version == MIPS_64)
16591666
instruction->operation = mips64_special3_table[ins.decode.func_hi][ins.decode.func_lo];
1667+
else if (version == MIPS_R5900)
1668+
instruction->operation = mips_base_table[version-1][ins.decode.op_hi][ins.decode.op_lo];
16601669
break;
16611670
default:
16621671
if ((flags & DECOMPOSE_FLAGS_CAVIUM) == 0)
@@ -2546,6 +2555,8 @@ uint32_t mips_decompose_instruction(
25462555
instruction->operands[0].reg = ins.i.rt;
25472556
instruction->operands[1].reg = ins.i.rs;
25482557
instruction->operands[1].immediate = ins.i.immediate;
2558+
if (instruction->operation == MIPS_SQ)
2559+
instruction->operands[1].immediate = MIPS_SQ;
25492560
break;
25502561
case MIPS_PREF:
25512562
case MIPS_PREFX:
@@ -2590,7 +2601,9 @@ uint32_t mips_decompose_instruction(
25902601
instruction->operands[0].operandClass = IMM;
25912602
instruction->operands[1].operandClass = MEM_IMM;
25922603
instruction->operands[0].reg = version != MIPS_R5900 ? ins.i.rt : (FPREG_F0 + ins.f.ft);
2593-
instruction->operands[1].reg = version != MIPS_R5900 ? ins.i.rs : (FPREG_F0 + ins.f.fr);
2604+
// This special case for the R5900 seems wrong: it's trying to use a FP register for the base register
2605+
// instruction->operands[1].reg = version != MIPS_R5900 ? ins.i.rs : (FPREG_F0 + ins.f.fr);
2606+
instruction->operands[1].reg = ins.i.rs;
25942607
instruction->operands[1].immediate = ins.i.immediate;
25952608
break;
25962609
//3 operand instructions

arch/mips/mips/mips.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1163,6 +1163,10 @@ namespace mips
11631163

11641164
R5900_SA,
11651165

1166+
// R5900 Special registers (upper 64 bits of $lo and $hi)
1167+
REG_LO1,
1168+
REG_HI1,
1169+
11661170
// Last valid register
11671171
END_REG
11681172
};
@@ -1335,6 +1339,7 @@ namespace mips
13351339
Operation operation;
13361340
InstructionOperand operands[MAX_OPERANDS];
13371341
uint32_t size;
1342+
uint32_t numOperands;
13381343
};
13391344

13401345
#ifndef __cplusplus

arch/mips/mips/test.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ int main(int ac, char **av)
7878
version = MIPS_3;
7979
else if (!strcmp("-mips4", av[1]))
8080
version = MIPS_4;
81+
else if (!strcmp("-r5900", av[1]))
82+
version = MIPS_R5900;
8183
else if (!strcmp("-cavium", av[1]))
8284
{
8385
version = MIPS_64;

0 commit comments

Comments
 (0)