Skip to content

Commit a8c277c

Browse files
authored
Merge pull request #222 from Prof9/fix-arm-thumb-immediate-checks
Fix up some ARM/THUMB immediates jank
2 parents ee166d2 + 0eaf3b5 commit a8c277c

File tree

11 files changed

+480
-47
lines changed

11 files changed

+480
-47
lines changed

Archs/ARM/ArmOpcodes.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,16 +52,16 @@ const tArmOpcode ArmOpcodes[] = {
5252
{ "xorCS", "d0,/#i", 0x02200000, ARM_TYPE5, ARM_SHIFT|ARM_D|ARM_IMMEDIATE|ARM_N|ARM_DN },
5353
{ "subCS", "d0,n0,m0S0", 0x00400000, ARM_TYPE5, ARM_REGISTER|ARM_D|ARM_M|ARM_N },
5454
{ "subCS", "d0,m0S0", 0x00400000, ARM_TYPE5, ARM_REGISTER|ARM_D|ARM_M|ARM_N|ARM_DN },
55-
{ "subCS", "d0,n0,/#i", 0x02400000, ARM_TYPE5, ARM_SHIFT|ARM_D|ARM_IMMEDIATE|ARM_N },
56-
{ "subCS", "d0,/#i", 0x02400000, ARM_TYPE5, ARM_SHIFT|ARM_D|ARM_IMMEDIATE|ARM_N|ARM_DN },
55+
{ "subCS", "d0,n0,/#i", 0x02400000, ARM_TYPE5, ARM_SHIFT|ARM_D|ARM_IMMEDIATE|ARM_N|ARM_OPTIMIZE|ARM_OPADDSUB },
56+
{ "subCS", "d0,/#i", 0x02400000, ARM_TYPE5, ARM_SHIFT|ARM_D|ARM_IMMEDIATE|ARM_N|ARM_DN|ARM_OPTIMIZE|ARM_OPADDSUB },
5757
{ "rsbCS", "d0,n0,m0S0", 0x00600000, ARM_TYPE5, ARM_REGISTER|ARM_D|ARM_M|ARM_N },
5858
{ "rsbCS", "d0,m0S0", 0x00600000, ARM_TYPE5, ARM_REGISTER|ARM_D|ARM_M|ARM_N|ARM_DN },
5959
{ "rsbCS", "d0,n0,/#i", 0x02600000, ARM_TYPE5, ARM_SHIFT|ARM_D|ARM_IMMEDIATE|ARM_N },
6060
{ "rsbCS", "d0,/#i", 0x02600000, ARM_TYPE5, ARM_SHIFT|ARM_D|ARM_IMMEDIATE|ARM_N|ARM_DN },
6161
{ "addCS", "d0,n0,m0S0", 0x00800000, ARM_TYPE5, ARM_REGISTER|ARM_D|ARM_M|ARM_N },
6262
{ "addCS", "d0,m0S0", 0x00800000, ARM_TYPE5, ARM_REGISTER|ARM_D|ARM_M|ARM_N|ARM_DN },
63-
{ "addCS", "d0,n0,/#i", 0x02800000, ARM_TYPE5, ARM_SHIFT|ARM_D|ARM_IMMEDIATE|ARM_N },
64-
{ "addCS", "d0,/#i", 0x02800000, ARM_TYPE5, ARM_SHIFT|ARM_D|ARM_IMMEDIATE|ARM_N|ARM_DN },
63+
{ "addCS", "d0,n0,/#i", 0x02800000, ARM_TYPE5, ARM_SHIFT|ARM_D|ARM_IMMEDIATE|ARM_N|ARM_OPTIMIZE|ARM_OPADDSUB },
64+
{ "addCS", "d0,/#i", 0x02800000, ARM_TYPE5, ARM_SHIFT|ARM_D|ARM_IMMEDIATE|ARM_N|ARM_DN|ARM_OPTIMIZE|ARM_OPADDSUB },
6565
{ "adcCS", "d0,n0,m0S0", 0x00A00000, ARM_TYPE5, ARM_REGISTER|ARM_D|ARM_M|ARM_N },
6666
{ "adcCS", "d0,m0S0", 0x00A00000, ARM_TYPE5, ARM_REGISTER|ARM_D|ARM_M|ARM_N|ARM_DN },
6767
{ "adcCS", "d0,n0,/#i", 0x02A00000, ARM_TYPE5, ARM_SHIFT|ARM_D|ARM_IMMEDIATE|ARM_N },

Archs/ARM/ArmOpcodes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
#define ARM_OPANDBIC 0x40000000 // ... of and/bic
5555
#define ARM_OPCMPCMN 0x80000000 // ... of cmp/cmn
5656
#define ARM_PCR 0x100000000 // pc relative
57+
#define ARM_OPADDSUB 0x200000000 // ... of add/sub
5758

5859
struct tArmOpcode
5960
{

Archs/ARM/CArmInstruction.cpp

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -239,18 +239,25 @@ bool CArmInstruction::Validate(const ValidateState &state)
239239
encoding ^= 0x0200000;
240240
immediate = 0-immediate;
241241
}
242+
else if (Opcode.flags & ARM_OPADDSUB)
243+
{
244+
encoding ^= 0x0C00000;
245+
immediate = 0-immediate;
246+
}
242247

243248
temp = getShiftedImmediate(immediate, Vars.Shift.ShiftAmount);
244249
if (temp != -1)
245250
{
246251
Vars.Opcode.NewEncoding = encoding;
247252
Vars.Opcode.UseNewEncoding = true;
248253
}
249-
else
250-
{
251-
Logger::queueError(Logger::Error, "Invalid shifted immediate %X",Vars.OriginalImmediate);
252-
return false;
253-
}
254+
}
255+
if (temp == -1)
256+
{
257+
// If we get here then the instruction did not contain a shifted immediate
258+
// and we failed to optimize into another instruction
259+
Logger::queueError(Logger::Error, "Invalid shifted immediate 0x%X", Vars.OriginalImmediate);
260+
return false;
254261
}
255262
}
256263
Vars.Immediate = temp;
@@ -327,7 +334,7 @@ bool CArmInstruction::Validate(const ValidateState &state)
327334
unsigned int check = Opcode.flags & ARM_ABS ? abs(Vars.Immediate) : Vars.Immediate;
328335
if (check >= (unsigned int)(1 << Vars.ImmediateBitLen))
329336
{
330-
Logger::queueError(Logger::Error, "Immediate value %X out of range",Vars.Immediate);
337+
Logger::queueError(Logger::Error, "Immediate value %X out of range",Vars.OriginalImmediate);
331338
return false;
332339
}
333340
}

Archs/ARM/CThumbInstruction.cpp

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ bool CThumbInstruction::Validate(const ValidateState &state)
3636
{
3737
RamPos = g_fileManager->getVirtualAddress();
3838

39+
Vars.UseNewEncoding = false;
40+
3941
if (RamPos & 1)
4042
{
4143
Logger::queueError(Logger::Warning, "Opcode not halfword aligned");
@@ -96,7 +98,7 @@ bool CThumbInstruction::Validate(const ValidateState &state)
9698

9799
if (num >= (1 << Vars.ImmediateBitLen) || num < (0-(1 << Vars.ImmediateBitLen)))
98100
{
99-
Logger::queueError(Logger::Error, "Branch target %08X out of range",Vars.Immediate);
101+
Logger::queueError(Logger::Error, "Branch target 0x%X out of range",Vars.OriginalImmediate);
100102
return false;
101103
}
102104

@@ -141,23 +143,54 @@ bool CThumbInstruction::Validate(const ValidateState &state)
141143
Vars.Immediate = pos >> 2;
142144
}
143145

146+
if (Opcode.flags & THUMB_ADDSUB_IMMEDIATE)
147+
{
148+
int max = (1 << Vars.ImmediateBitLen) - 1;
149+
if (-max <= Vars.Immediate && Vars.Immediate < 0)
150+
{
151+
Vars.UseNewEncoding = true;
152+
switch (Opcode.type)
153+
{
154+
case THUMB_TYPE2: // add rX,rY,imm
155+
Vars.NewEncoding = Opcode.encoding ^ 0x0200;
156+
break;
157+
case THUMB_TYPE3: // add rX,imm
158+
Vars.NewEncoding = Opcode.encoding ^ 0x0800;
159+
break;
160+
case THUMB_TYPE13: // add sp,imm
161+
Vars.NewEncoding = Opcode.encoding ^ 0x0080;
162+
break;
163+
default:
164+
Vars.UseNewEncoding = false;
165+
break;
166+
}
167+
if (Vars.UseNewEncoding)
168+
{
169+
Vars.Immediate = -Vars.Immediate;
170+
}
171+
}
172+
}
173+
144174
if (Opcode.type == THUMB_TYPE1)
145175
{
146176
int max = (Opcode.flags & THUMB_RIGHTSHIFT_IMMEDIATE) ? 32 : 31;
147177
if (Vars.Immediate < 0 || Vars.Immediate > max)
148178
{
149-
Logger::queueError(Logger::Error, "Shift amount 0x%02X out of range",Vars.Immediate);
179+
Logger::queueError(Logger::Error, "Shift amount 0x%X out of range", Vars.OriginalImmediate);
150180
return false;
151181
}
152-
} else if (Vars.ImmediateBitLen != 32)
182+
} else if (Opcode.flags & THUMB_BRANCH)
153183
{
154184
int max = (1 << Vars.ImmediateBitLen) - 1;
155-
if (abs(Vars.Immediate) > max)
185+
Vars.Immediate &= max;
186+
} else if (!(Opcode.flags & (THUMB_POOL | THUMB_PCR)))
187+
{
188+
int max = (1 << Vars.ImmediateBitLen) - 1;
189+
if (Vars.Immediate < 0 || Vars.Immediate > max)
156190
{
157-
Logger::queueError(Logger::Error, "Immediate value 0x%02X out of range",Vars.Immediate);
191+
Logger::queueError(Logger::Error, "Immediate value 0x%X out of range", Vars.OriginalImmediate);
158192
return false;
159193
}
160-
Vars.Immediate &= max;
161194
}
162195
}
163196

@@ -174,8 +207,7 @@ void CThumbInstruction::WriteInstruction(unsigned short encoding) const
174207

175208
void CThumbInstruction::Encode() const
176209
{
177-
unsigned int encoding = Opcode.encoding;
178-
int immediate;
210+
unsigned int encoding = Vars.UseNewEncoding ? Vars.NewEncoding : Opcode.encoding;
179211

180212
if (Opcode.type == THUMB_TYPE19) // THUMB.19: long branch with link
181213
{
@@ -262,16 +294,8 @@ void CThumbInstruction::Encode() const
262294
encoding |= (Vars.rd.num << 8);
263295
encoding |= (Vars.Immediate << 0);
264296
break;
265-
case THUMB_TYPE13: // THUMB.13: add offset to stack pointer
266-
immediate = Vars.Immediate;
267-
if (Opcode.flags & THUMB_NEGATIVE_IMMEDIATE)
268-
immediate = (unsigned char)(0-immediate);
269-
if (immediate & 0x80) // sub
270-
{
271-
encoding |= 1 << 7;
272-
immediate = 0x100-immediate;
273-
}
274-
encoding |= (immediate << 0);
297+
case THUMB_TYPE13: // THUMB.13: add/subtract offset to/from stack pointer
298+
encoding |= (Vars.Immediate << 0);
275299
break;
276300
case THUMB_TYPE14: // THUMB.14: push/pop registers
277301
if (Vars.rlist & 0xC000) encoding |= (1 << 8); // r14 oder r15

Archs/ARM/CThumbInstruction.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ struct ThumbOpcodeVariables {
1414
int ImmediateBitLen;
1515
int OriginalImmediate;
1616
int rlist;
17+
unsigned int NewEncoding;
18+
bool UseNewEncoding;
1719
char RlistStr[32];
1820
} ;
1921

Archs/ARM/ThumbOpcodes.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,14 @@ const tThumbOpcode ThumbOpcodes[] = {
3333
{ "add", "d,n", 0x1800, THUMB_TYPE2, 2, THUMB_REGISTER|THUMB_DS },
3434
{ "sub", "d,s,n", 0x1A00, THUMB_TYPE2, 2, THUMB_REGISTER },
3535
{ "sub", "d,n", 0x1A00, THUMB_TYPE2, 2, THUMB_REGISTER|THUMB_DS },
36-
{ "add", "d,s,/#i\x03", 0x1C00, THUMB_TYPE2, 2, THUMB_IMMEDIATE },
37-
{ "sub", "d,s,/#i\x03", 0x1E00, THUMB_TYPE2, 2, THUMB_IMMEDIATE },
36+
{ "add", "d,s,/#i\x03", 0x1C00, THUMB_TYPE2, 2, THUMB_IMMEDIATE|THUMB_ADDSUB_IMMEDIATE },
37+
{ "sub", "d,s,/#i\x03", 0x1E00, THUMB_TYPE2, 2, THUMB_IMMEDIATE|THUMB_ADDSUB_IMMEDIATE },
3838
{ "mov", "d,s", 0x1C00, THUMB_TYPE2, 2, 0 },
3939

4040
{ "mov", "d,/#i\x08", 0x2000, THUMB_TYPE3, 2, THUMB_IMMEDIATE },
4141
{ "cmp", "d,/#i\x08", 0x2800, THUMB_TYPE3, 2, THUMB_IMMEDIATE },
42-
{ "add", "d,/#i\x08", 0x3000, THUMB_TYPE3, 2, THUMB_IMMEDIATE },
43-
{ "sub", "d,/#i\x08", 0x3800, THUMB_TYPE3, 2, THUMB_IMMEDIATE },
42+
{ "add", "d,/#i\x08", 0x3000, THUMB_TYPE3, 2, THUMB_IMMEDIATE|THUMB_ADDSUB_IMMEDIATE },
43+
{ "sub", "d,/#i\x08", 0x3800, THUMB_TYPE3, 2, THUMB_IMMEDIATE|THUMB_ADDSUB_IMMEDIATE },
4444

4545
{ "and", "d,s", 0x4000, THUMB_TYPE4, 2, THUMB_REGISTER },
4646
{ "eor", "d,s", 0x4040, THUMB_TYPE4, 2, THUMB_REGISTER },
@@ -107,11 +107,11 @@ const tThumbOpcode ThumbOpcodes[] = {
107107
{ "add", "d,=/#i\x20", 0xA000, THUMB_TYPE12, 2, THUMB_D|THUMB_IMMEDIATE|THUMB_PCR },
108108
{ "add", "d,r\xD,/#i\x08", 0xA800, THUMB_TYPE12, 2, THUMB_D|THUMB_IMMEDIATE|THUMB_WORD },
109109

110-
{ "add", "r\xD,/#i\x08", 0xB000, THUMB_TYPE13, 2, THUMB_IMMEDIATE|THUMB_WORD },
111-
{ "sub", "r\xD,/#i\x08", 0xB000, THUMB_TYPE13, 2, THUMB_IMMEDIATE|THUMB_WORD|THUMB_NEGATIVE_IMMEDIATE },
110+
{ "add", "r\xD,/#i\x07", 0xB000, THUMB_TYPE13, 2, THUMB_IMMEDIATE|THUMB_WORD|THUMB_ADDSUB_IMMEDIATE },
111+
{ "sub", "r\xD,/#i\x07", 0xB080, THUMB_TYPE13, 2, THUMB_IMMEDIATE|THUMB_WORD|THUMB_ADDSUB_IMMEDIATE },
112112

113-
{ "add", "r\xD,r\xD,/#i\x08",0xB000, THUMB_TYPE13, 2, THUMB_IMMEDIATE|THUMB_WORD },
114-
{ "sub", "r\xD,r\xD,/#i\x08",0xB000, THUMB_TYPE13, 2, THUMB_IMMEDIATE|THUMB_WORD|THUMB_NEGATIVE_IMMEDIATE },
113+
{ "add", "r\xD,r\xD,/#i\x07",0xB000, THUMB_TYPE13, 2, THUMB_IMMEDIATE|THUMB_WORD|THUMB_ADDSUB_IMMEDIATE },
114+
{ "sub", "r\xD,r\xD,/#i\x07",0xB080, THUMB_TYPE13, 2, THUMB_IMMEDIATE|THUMB_WORD|THUMB_ADDSUB_IMMEDIATE },
115115

116116
{ "push", "/{R\xFF\x40/}", 0xB400, THUMB_TYPE14, 2, THUMB_RLIST },
117117
{ "pop", "/{R\xFF\x80/}", 0xBC00, THUMB_TYPE14, 2, THUMB_RLIST },

Archs/ARM/ThumbOpcodes.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
#define THUMB_PCR 0x00002000
3737
#define THUMB_DS 0x00004000 // rs = rd
3838
#define THUMB_PCADD 0x00008000
39-
#define THUMB_NEGATIVE_IMMEDIATE 0x00010000
39+
#define THUMB_ADDSUB_IMMEDIATE 0x00010000
4040
#define THUMB_RIGHTSHIFT_IMMEDIATE 0x00020000
4141

4242
struct tThumbOpcode

0 commit comments

Comments
 (0)