1 // Rar3Vm.cpp
2 // According to unRAR license, this code may not be used to develop
3 // a program that creates RAR archives
4
5 /*
6 Note:
7 Due to performance considerations Rar VM may set Flags C incorrectly
8 for some operands (SHL x, 0, ... ).
9 Check implementation of concrete VM command
10 to see if it sets flags right.
11 */
12
13 #include "StdAfx.h"
14
15 #include <stdlib.h>
16
17 #include "../../../C/7zCrc.h"
18 #include "../../../C/Alloc.h"
19
20 #include "../../Common/Defs.h"
21
22 #include "Rar3Vm.h"
23
24 namespace NCompress {
25 namespace NRar3 {
26
ReadBits(unsigned numBits)27 UInt32 CMemBitDecoder::ReadBits(unsigned numBits)
28 {
29 UInt32 res = 0;
30 for (;;)
31 {
32 unsigned b = _bitPos < _bitSize ? (unsigned)_data[_bitPos >> 3] : 0;
33 unsigned avail = (unsigned)(8 - (_bitPos & 7));
34 if (numBits <= avail)
35 {
36 _bitPos += numBits;
37 return res | ((b >> (avail - numBits)) & ((1 << numBits) - 1));
38 }
39 numBits -= avail;
40 res |= (UInt32)(b & ((1 << avail) - 1)) << numBits;
41 _bitPos += avail;
42 }
43 }
44
ReadBit()45 UInt32 CMemBitDecoder::ReadBit() { return ReadBits(1); }
46
ReadEncodedUInt32()47 UInt32 CMemBitDecoder::ReadEncodedUInt32()
48 {
49 unsigned v = (unsigned)ReadBits(2);
50 UInt32 res = ReadBits(4 << v);
51 if (v == 1 && res < 16)
52 res = 0xFFFFFF00 | (res << 4) | ReadBits(4);
53 return res;
54 }
55
56 namespace NVm {
57
58 static const UInt32 kStackRegIndex = kNumRegs - 1;
59
60 #ifdef RARVM_VM_ENABLE
61
62 static const UInt32 FLAG_C = 1;
63 static const UInt32 FLAG_Z = 2;
64 static const UInt32 FLAG_S = 0x80000000;
65
66 static const Byte CF_OP0 = 0;
67 static const Byte CF_OP1 = 1;
68 static const Byte CF_OP2 = 2;
69 static const Byte CF_OPMASK = 3;
70 static const Byte CF_BYTEMODE = 4;
71 static const Byte CF_JUMP = 8;
72 static const Byte CF_PROC = 16;
73 static const Byte CF_USEFLAGS = 32;
74 static const Byte CF_CHFLAGS = 64;
75
76 static const Byte kCmdFlags[]=
77 {
78 /* CMD_MOV */ CF_OP2 | CF_BYTEMODE,
79 /* CMD_CMP */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
80 /* CMD_ADD */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
81 /* CMD_SUB */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
82 /* CMD_JZ */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
83 /* CMD_JNZ */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
84 /* CMD_INC */ CF_OP1 | CF_BYTEMODE | CF_CHFLAGS,
85 /* CMD_DEC */ CF_OP1 | CF_BYTEMODE | CF_CHFLAGS,
86 /* CMD_JMP */ CF_OP1 | CF_JUMP,
87 /* CMD_XOR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
88 /* CMD_AND */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
89 /* CMD_OR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
90 /* CMD_TEST */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
91 /* CMD_JS */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
92 /* CMD_JNS */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
93 /* CMD_JB */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
94 /* CMD_JBE */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
95 /* CMD_JA */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
96 /* CMD_JAE */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
97 /* CMD_PUSH */ CF_OP1,
98 /* CMD_POP */ CF_OP1,
99 /* CMD_CALL */ CF_OP1 | CF_PROC,
100 /* CMD_RET */ CF_OP0 | CF_PROC,
101 /* CMD_NOT */ CF_OP1 | CF_BYTEMODE,
102 /* CMD_SHL */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
103 /* CMD_SHR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
104 /* CMD_SAR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
105 /* CMD_NEG */ CF_OP1 | CF_BYTEMODE | CF_CHFLAGS,
106 /* CMD_PUSHA */ CF_OP0,
107 /* CMD_POPA */ CF_OP0,
108 /* CMD_PUSHF */ CF_OP0 | CF_USEFLAGS,
109 /* CMD_POPF */ CF_OP0 | CF_CHFLAGS,
110 /* CMD_MOVZX */ CF_OP2,
111 /* CMD_MOVSX */ CF_OP2,
112 /* CMD_XCHG */ CF_OP2 | CF_BYTEMODE,
113 /* CMD_MUL */ CF_OP2 | CF_BYTEMODE,
114 /* CMD_DIV */ CF_OP2 | CF_BYTEMODE,
115 /* CMD_ADC */ CF_OP2 | CF_BYTEMODE | CF_USEFLAGS | CF_CHFLAGS ,
116 /* CMD_SBB */ CF_OP2 | CF_BYTEMODE | CF_USEFLAGS | CF_CHFLAGS ,
117 /* CMD_PRINT */ CF_OP0
118 };
119
120 #endif
121
122
CVm()123 CVm::CVm(): Mem(NULL) {}
124
Create()125 bool CVm::Create()
126 {
127 if (!Mem)
128 Mem = (Byte *)::MyAlloc(kSpaceSize + 4);
129 return (Mem != NULL);
130 }
131
~CVm()132 CVm::~CVm()
133 {
134 ::MyFree(Mem);
135 }
136
137 // CVm::Execute can change CProgram object: it clears progarm if VM returns error.
138
Execute(CProgram * prg,const CProgramInitState * initState,CBlockRef & outBlockRef,CRecordVector<Byte> & outGlobalData)139 bool CVm::Execute(CProgram *prg, const CProgramInitState *initState,
140 CBlockRef &outBlockRef, CRecordVector<Byte> &outGlobalData)
141 {
142 memcpy(R, initState->InitR, sizeof(initState->InitR));
143 R[kStackRegIndex] = kSpaceSize;
144 R[kNumRegs] = 0;
145 Flags = 0;
146
147 UInt32 globalSize = MyMin((UInt32)initState->GlobalData.Size(), kGlobalSize);
148 if (globalSize != 0)
149 memcpy(Mem + kGlobalOffset, &initState->GlobalData[0], globalSize);
150 UInt32 staticSize = MyMin((UInt32)prg->StaticData.Size(), kGlobalSize - globalSize);
151 if (staticSize != 0)
152 memcpy(Mem + kGlobalOffset + globalSize, &prg->StaticData[0], staticSize);
153
154 bool res = true;
155
156 #ifdef RARVM_STANDARD_FILTERS
157 if (prg->StandardFilterIndex >= 0)
158 res = ExecuteStandardFilter(prg->StandardFilterIndex);
159 else
160 #endif
161 {
162 #ifdef RARVM_VM_ENABLE
163 res = ExecuteCode(prg);
164 if (!res)
165 {
166 prg->Commands.Clear();
167 prg->Commands.Add(CCommand());
168 prg->Commands.Back().OpCode = CMD_RET;
169 }
170 #else
171 res = false;
172 #endif
173 }
174
175 UInt32 newBlockPos = GetFixedGlobalValue32(NGlobalOffset::kBlockPos) & kSpaceMask;
176 UInt32 newBlockSize = GetFixedGlobalValue32(NGlobalOffset::kBlockSize) & kSpaceMask;
177 if (newBlockPos + newBlockSize >= kSpaceSize)
178 newBlockPos = newBlockSize = 0;
179 outBlockRef.Offset = newBlockPos;
180 outBlockRef.Size = newBlockSize;
181
182 outGlobalData.Clear();
183 UInt32 dataSize = GetFixedGlobalValue32(NGlobalOffset::kGlobalMemOutSize);
184 dataSize = MyMin(dataSize, kGlobalSize - kFixedGlobalSize);
185 if (dataSize != 0)
186 {
187 dataSize += kFixedGlobalSize;
188 outGlobalData.ClearAndSetSize(dataSize);
189 memcpy(&outGlobalData[0], Mem + kGlobalOffset, dataSize);
190 }
191
192 return res;
193 }
194
195 #ifdef RARVM_VM_ENABLE
196
197 #define SET_IP(IP) \
198 if ((IP) >= numCommands) return true; \
199 if (--maxOpCount <= 0) return false; \
200 cmd = commands + (IP);
201
202 #define GET_FLAG_S_B(res) (((res) & 0x80) ? FLAG_S : 0)
203 #define SET_IP_OP1 { UInt32 val = GetOperand32(&cmd->Op1); SET_IP(val); }
204 #define FLAGS_UPDATE_SZ Flags = res == 0 ? FLAG_Z : res & FLAG_S
205 #define FLAGS_UPDATE_SZ_B Flags = (res & 0xFF) == 0 ? FLAG_Z : GET_FLAG_S_B(res)
206
GetOperand32(const COperand * op) const207 UInt32 CVm::GetOperand32(const COperand *op) const
208 {
209 switch (op->Type)
210 {
211 case OP_TYPE_REG: return R[op->Data];
212 case OP_TYPE_REGMEM: return GetValue32(&Mem[(op->Base + R[op->Data]) & kSpaceMask]);
213 default: return op->Data;
214 }
215 }
216
SetOperand32(const COperand * op,UInt32 val)217 void CVm::SetOperand32(const COperand *op, UInt32 val)
218 {
219 switch (op->Type)
220 {
221 case OP_TYPE_REG: R[op->Data] = val; return;
222 case OP_TYPE_REGMEM: SetValue32(&Mem[(op->Base + R[op->Data]) & kSpaceMask], val); return;
223 }
224 }
225
GetOperand8(const COperand * op) const226 Byte CVm::GetOperand8(const COperand *op) const
227 {
228 switch (op->Type)
229 {
230 case OP_TYPE_REG: return (Byte)R[op->Data];
231 case OP_TYPE_REGMEM: return Mem[(op->Base + R[op->Data]) & kSpaceMask];;
232 default: return (Byte)op->Data;
233 }
234 }
235
SetOperand8(const COperand * op,Byte val)236 void CVm::SetOperand8(const COperand *op, Byte val)
237 {
238 switch (op->Type)
239 {
240 case OP_TYPE_REG: R[op->Data] = (R[op->Data] & 0xFFFFFF00) | val; return;
241 case OP_TYPE_REGMEM: Mem[(op->Base + R[op->Data]) & kSpaceMask] = val; return;
242 }
243 }
244
GetOperand(bool byteMode,const COperand * op) const245 UInt32 CVm::GetOperand(bool byteMode, const COperand *op) const
246 {
247 if (byteMode)
248 return GetOperand8(op);
249 return GetOperand32(op);
250 }
251
SetOperand(bool byteMode,const COperand * op,UInt32 val)252 void CVm::SetOperand(bool byteMode, const COperand *op, UInt32 val)
253 {
254 if (byteMode)
255 SetOperand8(op, (Byte)(val & 0xFF));
256 else
257 SetOperand32(op, val);
258 }
259
ExecuteCode(const CProgram * prg)260 bool CVm::ExecuteCode(const CProgram *prg)
261 {
262 Int32 maxOpCount = 25000000;
263 const CCommand *commands = &prg->Commands[0];
264 const CCommand *cmd = commands;
265 UInt32 numCommands = prg->Commands.Size();
266 if (numCommands == 0)
267 return false;
268
269 for (;;)
270 {
271 switch (cmd->OpCode)
272 {
273 case CMD_MOV:
274 SetOperand32(&cmd->Op1, GetOperand32(&cmd->Op2));
275 break;
276 case CMD_MOVB:
277 SetOperand8(&cmd->Op1, GetOperand8(&cmd->Op2));
278 break;
279 case CMD_CMP:
280 {
281 UInt32 v1 = GetOperand32(&cmd->Op1);
282 UInt32 res = v1 - GetOperand32(&cmd->Op2);
283 Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S);
284 }
285 break;
286 case CMD_CMPB:
287 {
288 Byte v1 = GetOperand8(&cmd->Op1);
289 Byte res = (Byte)((v1 - GetOperand8(&cmd->Op2)) & 0xFF);
290 Flags = res == 0 ? FLAG_Z : (res > v1) | GET_FLAG_S_B(res);
291 }
292 break;
293 case CMD_ADD:
294 {
295 UInt32 v1 = GetOperand32(&cmd->Op1);
296 UInt32 res = v1 + GetOperand32(&cmd->Op2);
297 SetOperand32(&cmd->Op1, res);
298 Flags = (res < v1) | (res == 0 ? FLAG_Z : (res & FLAG_S));
299 }
300 break;
301 case CMD_ADDB:
302 {
303 Byte v1 = GetOperand8(&cmd->Op1);
304 Byte res = (Byte)((v1 + GetOperand8(&cmd->Op2)) & 0xFF);
305 SetOperand8(&cmd->Op1, (Byte)res);
306 Flags = (res < v1) | (res == 0 ? FLAG_Z : GET_FLAG_S_B(res));
307 }
308 break;
309 case CMD_ADC:
310 {
311 UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1);
312 UInt32 FC = (Flags & FLAG_C);
313 UInt32 res = v1 + GetOperand(cmd->ByteMode, &cmd->Op2) + FC;
314 if (cmd->ByteMode)
315 res &= 0xFF;
316 SetOperand(cmd->ByteMode, &cmd->Op1, res);
317 Flags = (res < v1 || res == v1 && FC) | (res == 0 ? FLAG_Z : (res & FLAG_S));
318 }
319 break;
320 case CMD_SUB:
321 {
322 UInt32 v1 = GetOperand32(&cmd->Op1);
323 UInt32 res = v1 - GetOperand32(&cmd->Op2);
324 SetOperand32(&cmd->Op1, res);
325 Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S);
326 }
327 break;
328 case CMD_SUBB:
329 {
330 UInt32 v1 = GetOperand8(&cmd->Op1);
331 UInt32 res = v1 - GetOperand8(&cmd->Op2);
332 SetOperand8(&cmd->Op1, (Byte)res);
333 Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S);
334 }
335 break;
336 case CMD_SBB:
337 {
338 UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1);
339 UInt32 FC = (Flags & FLAG_C);
340 UInt32 res = v1 - GetOperand(cmd->ByteMode, &cmd->Op2) - FC;
341 // Flags = res == 0 ? FLAG_Z : (res > v1 || res == v1 && FC) | (res & FLAG_S);
342 if (cmd->ByteMode)
343 res &= 0xFF;
344 SetOperand(cmd->ByteMode, &cmd->Op1, res);
345 Flags = (res > v1 || res == v1 && FC) | (res == 0 ? FLAG_Z : (res & FLAG_S));
346 }
347 break;
348 case CMD_INC:
349 {
350 UInt32 res = GetOperand32(&cmd->Op1) + 1;
351 SetOperand32(&cmd->Op1, res);
352 FLAGS_UPDATE_SZ;
353 }
354 break;
355 case CMD_INCB:
356 {
357 Byte res = (Byte)(GetOperand8(&cmd->Op1) + 1);
358 SetOperand8(&cmd->Op1, res);;
359 FLAGS_UPDATE_SZ_B;
360 }
361 break;
362 case CMD_DEC:
363 {
364 UInt32 res = GetOperand32(&cmd->Op1) - 1;
365 SetOperand32(&cmd->Op1, res);
366 FLAGS_UPDATE_SZ;
367 }
368 break;
369 case CMD_DECB:
370 {
371 Byte res = (Byte)(GetOperand8(&cmd->Op1) - 1);
372 SetOperand8(&cmd->Op1, res);;
373 FLAGS_UPDATE_SZ_B;
374 }
375 break;
376 case CMD_XOR:
377 {
378 UInt32 res = GetOperand32(&cmd->Op1) ^ GetOperand32(&cmd->Op2);
379 SetOperand32(&cmd->Op1, res);
380 FLAGS_UPDATE_SZ;
381 }
382 break;
383 case CMD_XORB:
384 {
385 Byte res = (Byte)(GetOperand8(&cmd->Op1) ^ GetOperand8(&cmd->Op2));
386 SetOperand8(&cmd->Op1, res);
387 FLAGS_UPDATE_SZ_B;
388 }
389 break;
390 case CMD_AND:
391 {
392 UInt32 res = GetOperand32(&cmd->Op1) & GetOperand32(&cmd->Op2);
393 SetOperand32(&cmd->Op1, res);
394 FLAGS_UPDATE_SZ;
395 }
396 break;
397 case CMD_ANDB:
398 {
399 Byte res = (Byte)(GetOperand8(&cmd->Op1) & GetOperand8(&cmd->Op2));
400 SetOperand8(&cmd->Op1, res);
401 FLAGS_UPDATE_SZ_B;
402 }
403 break;
404 case CMD_OR:
405 {
406 UInt32 res = GetOperand32(&cmd->Op1) | GetOperand32(&cmd->Op2);
407 SetOperand32(&cmd->Op1, res);
408 FLAGS_UPDATE_SZ;
409 }
410 break;
411 case CMD_ORB:
412 {
413 Byte res = (Byte)(GetOperand8(&cmd->Op1) | GetOperand8(&cmd->Op2));
414 SetOperand8(&cmd->Op1, res);
415 FLAGS_UPDATE_SZ_B;
416 }
417 break;
418 case CMD_TEST:
419 {
420 UInt32 res = GetOperand32(&cmd->Op1) & GetOperand32(&cmd->Op2);
421 FLAGS_UPDATE_SZ;
422 }
423 break;
424 case CMD_TESTB:
425 {
426 Byte res = (Byte)(GetOperand8(&cmd->Op1) & GetOperand8(&cmd->Op2));
427 FLAGS_UPDATE_SZ_B;
428 }
429 break;
430 case CMD_NOT:
431 SetOperand(cmd->ByteMode, &cmd->Op1, ~GetOperand(cmd->ByteMode, &cmd->Op1));
432 break;
433 case CMD_NEG:
434 {
435 UInt32 res = 0 - GetOperand32(&cmd->Op1);
436 SetOperand32(&cmd->Op1, res);
437 Flags = res == 0 ? FLAG_Z : FLAG_C | (res & FLAG_S);
438 }
439 break;
440 case CMD_NEGB:
441 {
442 Byte res = (Byte)(0 - GetOperand8(&cmd->Op1));
443 SetOperand8(&cmd->Op1, res);
444 Flags = res == 0 ? FLAG_Z : FLAG_C | GET_FLAG_S_B(res);
445 }
446 break;
447
448 case CMD_SHL:
449 {
450 UInt32 v1 = GetOperand32(&cmd->Op1);
451 int v2 = (int)GetOperand32(&cmd->Op2);
452 UInt32 res = v1 << v2;
453 SetOperand32(&cmd->Op1, res);
454 Flags = (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 << (v2 - 1)) & 0x80000000 ? FLAG_C : 0);
455 }
456 break;
457 case CMD_SHLB:
458 {
459 Byte v1 = GetOperand8(&cmd->Op1);
460 int v2 = (int)GetOperand8(&cmd->Op2);
461 Byte res = (Byte)(v1 << v2);
462 SetOperand8(&cmd->Op1, res);
463 Flags = (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 << (v2 - 1)) & 0x80 ? FLAG_C : 0);
464 }
465 break;
466 case CMD_SHR:
467 {
468 UInt32 v1 = GetOperand32(&cmd->Op1);
469 int v2 = (int)GetOperand32(&cmd->Op2);
470 UInt32 res = v1 >> v2;
471 SetOperand32(&cmd->Op1, res);
472 Flags = (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 >> (v2 - 1)) & FLAG_C);
473 }
474 break;
475 case CMD_SHRB:
476 {
477 Byte v1 = GetOperand8(&cmd->Op1);
478 int v2 = (int)GetOperand8(&cmd->Op2);
479 Byte res = (Byte)(v1 >> v2);
480 SetOperand8(&cmd->Op1, res);
481 Flags = (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 >> (v2 - 1)) & FLAG_C);
482 }
483 break;
484 case CMD_SAR:
485 {
486 UInt32 v1 = GetOperand32(&cmd->Op1);
487 int v2 = (int)GetOperand32(&cmd->Op2);
488 UInt32 res = UInt32(((Int32)v1) >> v2);
489 SetOperand32(&cmd->Op1, res);
490 Flags= (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 >> (v2 - 1)) & FLAG_C);
491 }
492 break;
493 case CMD_SARB:
494 {
495 Byte v1 = GetOperand8(&cmd->Op1);
496 int v2 = (int)GetOperand8(&cmd->Op2);
497 Byte res = (Byte)(((signed char)v1) >> v2);
498 SetOperand8(&cmd->Op1, res);
499 Flags= (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 >> (v2 - 1)) & FLAG_C);
500 }
501 break;
502
503 case CMD_JMP:
504 SET_IP_OP1;
505 continue;
506 case CMD_JZ:
507 if ((Flags & FLAG_Z) != 0)
508 {
509 SET_IP_OP1;
510 continue;
511 }
512 break;
513 case CMD_JNZ:
514 if ((Flags & FLAG_Z) == 0)
515 {
516 SET_IP_OP1;
517 continue;
518 }
519 break;
520 case CMD_JS:
521 if ((Flags & FLAG_S) != 0)
522 {
523 SET_IP_OP1;
524 continue;
525 }
526 break;
527 case CMD_JNS:
528 if ((Flags & FLAG_S) == 0)
529 {
530 SET_IP_OP1;
531 continue;
532 }
533 break;
534 case CMD_JB:
535 if ((Flags & FLAG_C) != 0)
536 {
537 SET_IP_OP1;
538 continue;
539 }
540 break;
541 case CMD_JBE:
542 if ((Flags & (FLAG_C | FLAG_Z)) != 0)
543 {
544 SET_IP_OP1;
545 continue;
546 }
547 break;
548 case CMD_JA:
549 if ((Flags & (FLAG_C | FLAG_Z)) == 0)
550 {
551 SET_IP_OP1;
552 continue;
553 }
554 break;
555 case CMD_JAE:
556 if ((Flags & FLAG_C) == 0)
557 {
558 SET_IP_OP1;
559 continue;
560 }
561 break;
562
563 case CMD_PUSH:
564 R[kStackRegIndex] -= 4;
565 SetValue32(&Mem[R[kStackRegIndex] & kSpaceMask], GetOperand32(&cmd->Op1));
566 break;
567 case CMD_POP:
568 SetOperand32(&cmd->Op1, GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask]));
569 R[kStackRegIndex] += 4;
570 break;
571 case CMD_CALL:
572 R[kStackRegIndex] -= 4;
573 SetValue32(&Mem[R[kStackRegIndex] & kSpaceMask], (UInt32)(cmd - commands + 1));
574 SET_IP_OP1;
575 continue;
576
577 case CMD_PUSHA:
578 {
579 for (UInt32 i = 0, SP = R[kStackRegIndex] - 4; i < kNumRegs; i++, SP -= 4)
580 SetValue32(&Mem[SP & kSpaceMask], R[i]);
581 R[kStackRegIndex] -= kNumRegs * 4;
582 }
583 break;
584 case CMD_POPA:
585 {
586 for (UInt32 i = 0, SP = R[kStackRegIndex]; i < kNumRegs; i++, SP += 4)
587 R[kStackRegIndex - i] = GetValue32(&Mem[SP & kSpaceMask]);
588 }
589 break;
590 case CMD_PUSHF:
591 R[kStackRegIndex] -= 4;
592 SetValue32(&Mem[R[kStackRegIndex]&kSpaceMask], Flags);
593 break;
594 case CMD_POPF:
595 Flags = GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask]);
596 R[kStackRegIndex] += 4;
597 break;
598
599 case CMD_MOVZX:
600 SetOperand32(&cmd->Op1, GetOperand8(&cmd->Op2));
601 break;
602 case CMD_MOVSX:
603 SetOperand32(&cmd->Op1, (UInt32)(Int32)(signed char)GetOperand8(&cmd->Op2));
604 break;
605 case CMD_XCHG:
606 {
607 UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1);
608 SetOperand(cmd->ByteMode, &cmd->Op1, GetOperand(cmd->ByteMode, &cmd->Op2));
609 SetOperand(cmd->ByteMode, &cmd->Op2, v1);
610 }
611 break;
612 case CMD_MUL:
613 {
614 UInt32 res = GetOperand32(&cmd->Op1) * GetOperand32(&cmd->Op2);
615 SetOperand32(&cmd->Op1, res);
616 }
617 break;
618 case CMD_MULB:
619 {
620 Byte res = (Byte)(GetOperand8(&cmd->Op1) * GetOperand8(&cmd->Op2));
621 SetOperand8(&cmd->Op1, res);
622 }
623 break;
624 case CMD_DIV:
625 {
626 UInt32 divider = GetOperand(cmd->ByteMode, &cmd->Op2);
627 if (divider != 0)
628 {
629 UInt32 res = GetOperand(cmd->ByteMode, &cmd->Op1) / divider;
630 SetOperand(cmd->ByteMode, &cmd->Op1, res);
631 }
632 }
633 break;
634
635 case CMD_RET:
636 {
637 if (R[kStackRegIndex] >= kSpaceSize)
638 return true;
639 UInt32 ip = GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask]);
640 SET_IP(ip);
641 R[kStackRegIndex] += 4;
642 continue;
643 }
644 case CMD_PRINT:
645 break;
646 }
647 cmd++;
648 --maxOpCount;
649 }
650 }
651
652 //////////////////////////////////////////////////////
653 // Read program
654
DecodeArg(CMemBitDecoder & inp,COperand & op,bool byteMode)655 static void DecodeArg(CMemBitDecoder &inp, COperand &op, bool byteMode)
656 {
657 if (inp.ReadBit())
658 {
659 op.Type = OP_TYPE_REG;
660 op.Data = inp.ReadBits(kNumRegBits);
661 }
662 else if (inp.ReadBit() == 0)
663 {
664 op.Type = OP_TYPE_INT;
665 if (byteMode)
666 op.Data = inp.ReadBits(8);
667 else
668 op.Data = inp.ReadEncodedUInt32();
669 }
670 else
671 {
672 op.Type = OP_TYPE_REGMEM;
673 if (inp.ReadBit() == 0)
674 {
675 op.Data = inp.ReadBits(kNumRegBits);
676 op.Base = 0;
677 }
678 else
679 {
680 if (inp.ReadBit() == 0)
681 op.Data = inp.ReadBits(kNumRegBits);
682 else
683 op.Data = kNumRegs;
684 op.Base = inp.ReadEncodedUInt32();
685 }
686 }
687 }
688
ReadProgram(const Byte * code,UInt32 codeSize)689 void CProgram::ReadProgram(const Byte *code, UInt32 codeSize)
690 {
691 CMemBitDecoder inp;
692 inp.Init(code, codeSize);
693
694 StaticData.Clear();
695
696 if (inp.ReadBit())
697 {
698 UInt32 dataSize = inp.ReadEncodedUInt32() + 1;
699 for (UInt32 i = 0; inp.Avail() && i < dataSize; i++)
700 StaticData.Add((Byte)inp.ReadBits(8));
701 }
702
703 while (inp.Avail())
704 {
705 Commands.Add(CCommand());
706 CCommand *cmd = &Commands.Back();
707
708 if (inp.ReadBit() == 0)
709 cmd->OpCode = (ECommand)inp.ReadBits(3);
710 else
711 cmd->OpCode = (ECommand)(8 + inp.ReadBits(5));
712
713 if (kCmdFlags[(unsigned)cmd->OpCode] & CF_BYTEMODE)
714 cmd->ByteMode = (inp.ReadBit()) ? true : false;
715 else
716 cmd->ByteMode = 0;
717
718 int opNum = (kCmdFlags[(unsigned)cmd->OpCode] & CF_OPMASK);
719
720 if (opNum > 0)
721 {
722 DecodeArg(inp, cmd->Op1, cmd->ByteMode);
723 if (opNum == 2)
724 DecodeArg(inp, cmd->Op2, cmd->ByteMode);
725 else
726 {
727 if (cmd->Op1.Type == OP_TYPE_INT && (kCmdFlags[(unsigned)cmd->OpCode] & (CF_JUMP | CF_PROC)))
728 {
729 int dist = cmd->Op1.Data;
730 if (dist >= 256)
731 dist -= 256;
732 else
733 {
734 if (dist >= 136)
735 dist -= 264;
736 else if (dist >= 16)
737 dist -= 8;
738 else if (dist >= 8)
739 dist -= 16;
740 dist += Commands.Size() - 1;
741 }
742 cmd->Op1.Data = dist;
743 }
744 }
745 }
746
747 if (cmd->ByteMode)
748 {
749 switch (cmd->OpCode)
750 {
751 case CMD_MOV: cmd->OpCode = CMD_MOVB; break;
752 case CMD_CMP: cmd->OpCode = CMD_CMPB; break;
753 case CMD_ADD: cmd->OpCode = CMD_ADDB; break;
754 case CMD_SUB: cmd->OpCode = CMD_SUBB; break;
755 case CMD_INC: cmd->OpCode = CMD_INCB; break;
756 case CMD_DEC: cmd->OpCode = CMD_DECB; break;
757 case CMD_XOR: cmd->OpCode = CMD_XORB; break;
758 case CMD_AND: cmd->OpCode = CMD_ANDB; break;
759 case CMD_OR: cmd->OpCode = CMD_ORB; break;
760 case CMD_TEST: cmd->OpCode = CMD_TESTB; break;
761 case CMD_NEG: cmd->OpCode = CMD_NEGB; break;
762 case CMD_SHL: cmd->OpCode = CMD_SHLB; break;
763 case CMD_SHR: cmd->OpCode = CMD_SHRB; break;
764 case CMD_SAR: cmd->OpCode = CMD_SARB; break;
765 case CMD_MUL: cmd->OpCode = CMD_MULB; break;
766 }
767 }
768 }
769 }
770
771 #endif
772
773
774 #ifdef RARVM_STANDARD_FILTERS
775
776 enum EStandardFilter
777 {
778 SF_E8,
779 SF_E8E9,
780 SF_ITANIUM,
781 SF_RGB,
782 SF_AUDIO,
783 SF_DELTA
784 // SF_UPCASE
785 };
786
787 static const struct CStandardFilterSignature
788 {
789 UInt32 Length;
790 UInt32 CRC;
791 EStandardFilter Type;
792 }
793 kStdFilters[]=
794 {
795 { 53, 0xad576887, SF_E8 },
796 { 57, 0x3cd7e57e, SF_E8E9 },
797 { 120, 0x3769893f, SF_ITANIUM },
798 { 29, 0x0e06077d, SF_DELTA },
799 { 149, 0x1c2c5dc8, SF_RGB },
800 { 216, 0xbc85e701, SF_AUDIO }
801 // { 40, 0x46b9c560, SF_UPCASE }
802 };
803
FindStandardFilter(const Byte * code,UInt32 codeSize)804 static int FindStandardFilter(const Byte *code, UInt32 codeSize)
805 {
806 UInt32 crc = CrcCalc(code, codeSize);
807 for (unsigned i = 0; i < ARRAY_SIZE(kStdFilters); i++)
808 {
809 const CStandardFilterSignature &sfs = kStdFilters[i];
810 if (sfs.CRC == crc && sfs.Length == codeSize)
811 return i;
812 }
813 return -1;
814 }
815
816 #endif
817
818
PrepareProgram(const Byte * code,UInt32 codeSize)819 bool CProgram::PrepareProgram(const Byte *code, UInt32 codeSize)
820 {
821 IsSupported = false;
822
823 #ifdef RARVM_VM_ENABLE
824 Commands.Clear();
825 #endif
826
827 #ifdef RARVM_STANDARD_FILTERS
828 StandardFilterIndex = -1;
829 #endif
830
831 bool isOK = false;
832
833 Byte xorSum = 0;
834 for (UInt32 i = 0; i < codeSize; i++)
835 xorSum ^= code[i];
836
837 if (xorSum == 0 && codeSize != 0)
838 {
839 IsSupported = true;
840 isOK = true;
841 #ifdef RARVM_STANDARD_FILTERS
842 StandardFilterIndex = FindStandardFilter(code, codeSize);
843 if (StandardFilterIndex >= 0)
844 return true;
845 #endif
846
847 #ifdef RARVM_VM_ENABLE
848 ReadProgram(code + 1, codeSize - 1);
849 #else
850 IsSupported = false;
851 #endif
852 }
853
854 #ifdef RARVM_VM_ENABLE
855 Commands.Add(CCommand());
856 Commands.Back().OpCode = CMD_RET;
857 #endif
858
859 return isOK;
860 }
861
SetMemory(UInt32 pos,const Byte * data,UInt32 dataSize)862 void CVm::SetMemory(UInt32 pos, const Byte *data, UInt32 dataSize)
863 {
864 if (pos < kSpaceSize && data != Mem + pos)
865 memmove(Mem + pos, data, MyMin(dataSize, kSpaceSize - pos));
866 }
867
868 #ifdef RARVM_STANDARD_FILTERS
869
E8E9Decode(Byte * data,UInt32 dataSize,UInt32 fileOffset,bool e9)870 static void E8E9Decode(Byte *data, UInt32 dataSize, UInt32 fileOffset, bool e9)
871 {
872 if (dataSize <= 4)
873 return;
874 dataSize -= 4;
875 const UInt32 kFileSize = 0x1000000;
876 Byte cmpMask = (Byte)(e9 ? 0xFE : 0xFF);
877 for (UInt32 curPos = 0; curPos < dataSize;)
878 {
879 curPos++;
880 if (((*data++) & cmpMask) == 0xE8)
881 {
882 UInt32 offset = curPos + fileOffset;
883 UInt32 addr = GetValue32(data);
884 if (addr < kFileSize)
885 SetValue32(data, addr - offset);
886 else if ((addr & 0x80000000) != 0 && ((addr + offset) & 0x80000000) == 0)
887 SetValue32(data, addr + kFileSize);
888 data += 4;
889 curPos += 4;
890 }
891 }
892 }
893
894
ItaniumDecode(Byte * data,UInt32 dataSize,UInt32 fileOffset)895 static void ItaniumDecode(Byte *data, UInt32 dataSize, UInt32 fileOffset)
896 {
897 if (dataSize <= 21)
898 return;
899 fileOffset >>= 4;
900 dataSize -= 21;
901 dataSize += 15;
902 dataSize >>= 4;
903 dataSize += fileOffset;
904 do
905 {
906 unsigned m = ((UInt32)0x334B0000 >> (data[0] & 0x1E)) & 3;
907 if (m)
908 {
909 m++;
910 do
911 {
912 Byte *p = data + ((size_t)m * 5 - 8);
913 if (((p[3] >> m) & 15) == 5)
914 {
915 const UInt32 kMask = 0xFFFFF;
916 // UInt32 raw = ((UInt32)p[0]) | ((UInt32)p[1] << 8) | ((UInt32)p[2] << 16);
917 UInt32 raw = GetUi32(p);
918 UInt32 v = raw >> m;
919 v -= fileOffset;
920 v &= kMask;
921 raw &= ~(kMask << m);
922 raw |= (v << m);
923 // p[0] = (Byte)raw; p[1] = (Byte)(raw >> 8); p[2] = (Byte)(raw >> 16);
924 SetUi32(p, raw);
925 }
926 }
927 while (++m <= 4);
928 }
929 data += 16;
930 }
931 while (++fileOffset != dataSize);
932 }
933
934
DeltaDecode(Byte * data,UInt32 dataSize,UInt32 numChannels)935 static void DeltaDecode(Byte *data, UInt32 dataSize, UInt32 numChannels)
936 {
937 UInt32 srcPos = 0;
938 const UInt32 border = dataSize * 2;
939 for (UInt32 curChannel = 0; curChannel < numChannels; curChannel++)
940 {
941 Byte prevByte = 0;
942 for (UInt32 destPos = dataSize + curChannel; destPos < border; destPos += numChannels)
943 data[destPos] = (prevByte = (Byte)(prevByte - data[srcPos++]));
944 }
945 }
946
RgbDecode(Byte * srcData,UInt32 dataSize,UInt32 width,UInt32 posR)947 static void RgbDecode(Byte *srcData, UInt32 dataSize, UInt32 width, UInt32 posR)
948 {
949 Byte *destData = srcData + dataSize;
950 const UInt32 kNumChannels = 3;
951
952 for (UInt32 curChannel = 0; curChannel < kNumChannels; curChannel++)
953 {
954 Byte prevByte = 0;
955
956 for (UInt32 i = curChannel; i < dataSize; i += kNumChannels)
957 {
958 unsigned int predicted;
959 if (i < width)
960 predicted = prevByte;
961 else
962 {
963 unsigned int upperLeftByte = destData[i - width];
964 unsigned int upperByte = destData[i - width + 3];
965 predicted = prevByte + upperByte - upperLeftByte;
966 int pa = abs((int)(predicted - prevByte));
967 int pb = abs((int)(predicted - upperByte));
968 int pc = abs((int)(predicted - upperLeftByte));
969 if (pa <= pb && pa <= pc)
970 predicted = prevByte;
971 else
972 if (pb <= pc)
973 predicted = upperByte;
974 else
975 predicted = upperLeftByte;
976 }
977 destData[i] = prevByte = (Byte)(predicted - *(srcData++));
978 }
979 }
980 if (dataSize < 3)
981 return;
982 const UInt32 border = dataSize - 2;
983 for (UInt32 i = posR; i < border; i += 3)
984 {
985 Byte g = destData[i + 1];
986 destData[i ] = (Byte)(destData[i ] + g);
987 destData[i + 2] = (Byte)(destData[i + 2] + g);
988 }
989 }
990
AudioDecode(Byte * srcData,UInt32 dataSize,UInt32 numChannels)991 static void AudioDecode(Byte *srcData, UInt32 dataSize, UInt32 numChannels)
992 {
993 Byte *destData = srcData + dataSize;
994 for (UInt32 curChannel = 0; curChannel < numChannels; curChannel++)
995 {
996 UInt32 prevByte = 0, prevDelta = 0, dif[7];
997 Int32 D1 = 0, D2 = 0, D3;
998 Int32 K1 = 0, K2 = 0, K3 = 0;
999 memset(dif, 0, sizeof(dif));
1000
1001 for (UInt32 i = curChannel, byteCount = 0; i < dataSize; i += numChannels, byteCount++)
1002 {
1003 D3 = D2;
1004 D2 = prevDelta - D1;
1005 D1 = prevDelta;
1006
1007 UInt32 predicted = 8 * prevByte + K1 * D1 + K2 * D2 + K3 * D3;
1008 predicted = (predicted >> 3) & 0xFF;
1009
1010 UInt32 curByte = *(srcData++);
1011
1012 predicted -= curByte;
1013 destData[i] = (Byte)predicted;
1014 prevDelta = (UInt32)(Int32)(signed char)(predicted - prevByte);
1015 prevByte = predicted;
1016
1017 Int32 D = ((Int32)(signed char)curByte) << 3;
1018
1019 dif[0] += abs(D);
1020 dif[1] += abs(D - D1);
1021 dif[2] += abs(D + D1);
1022 dif[3] += abs(D - D2);
1023 dif[4] += abs(D + D2);
1024 dif[5] += abs(D - D3);
1025 dif[6] += abs(D + D3);
1026
1027 if ((byteCount & 0x1F) == 0)
1028 {
1029 UInt32 minDif = dif[0], numMinDif = 0;
1030 dif[0] = 0;
1031 for (unsigned j = 1; j < ARRAY_SIZE(dif); j++)
1032 {
1033 if (dif[j] < minDif)
1034 {
1035 minDif = dif[j];
1036 numMinDif = j;
1037 }
1038 dif[j] = 0;
1039 }
1040 switch (numMinDif)
1041 {
1042 case 1: if (K1 >= -16) K1--; break;
1043 case 2: if (K1 < 16) K1++; break;
1044 case 3: if (K2 >= -16) K2--; break;
1045 case 4: if (K2 < 16) K2++; break;
1046 case 5: if (K3 >= -16) K3--; break;
1047 case 6: if (K3 < 16) K3++; break;
1048 }
1049 }
1050 }
1051 }
1052 }
1053
1054 /*
1055 static UInt32 UpCaseDecode(Byte *data, UInt32 dataSize)
1056 {
1057 UInt32 srcPos = 0, destPos = dataSize;
1058 while (srcPos < dataSize)
1059 {
1060 Byte curByte = data[srcPos++];
1061 if (curByte == 2 && (curByte = data[srcPos++]) != 2)
1062 curByte -= 32;
1063 data[destPos++] = curByte;
1064 }
1065 return destPos - dataSize;
1066 }
1067 */
1068
ExecuteStandardFilter(unsigned filterIndex)1069 bool CVm::ExecuteStandardFilter(unsigned filterIndex)
1070 {
1071 UInt32 dataSize = R[4];
1072 if (dataSize >= kGlobalOffset)
1073 return false;
1074 EStandardFilter filterType = kStdFilters[filterIndex].Type;
1075
1076 switch (filterType)
1077 {
1078 case SF_E8:
1079 case SF_E8E9:
1080 E8E9Decode(Mem, dataSize, R[6], (filterType == SF_E8E9));
1081 break;
1082
1083 case SF_ITANIUM:
1084 ItaniumDecode(Mem, dataSize, R[6]);
1085 break;
1086
1087 case SF_DELTA:
1088 {
1089 if (dataSize >= kGlobalOffset / 2)
1090 return false;
1091 UInt32 numChannels = R[0];
1092 if (numChannels == 0 || numChannels > 1024) // unrar 5.5.5
1093 return false;
1094 SetBlockPos(dataSize);
1095 DeltaDecode(Mem, dataSize, numChannels);
1096 break;
1097 }
1098
1099 case SF_RGB:
1100 {
1101 if (dataSize >= kGlobalOffset / 2 || dataSize < 3) // unrar 5.5.5
1102 return false;
1103 UInt32 width = R[0];
1104 UInt32 posR = R[1];
1105 if (width < 3 || width - 3 > dataSize || posR > 2) // unrar 5.5.5
1106 return false;
1107 SetBlockPos(dataSize);
1108 RgbDecode(Mem, dataSize, width, posR);
1109 break;
1110 }
1111
1112 case SF_AUDIO:
1113 {
1114 if (dataSize >= kGlobalOffset / 2)
1115 return false;
1116 UInt32 numChannels = R[0];
1117 if (numChannels == 0 || numChannels > 128) // unrar 5.5.5
1118 return false;
1119 SetBlockPos(dataSize);
1120 AudioDecode(Mem, dataSize, numChannels);
1121 break;
1122 }
1123
1124 /*
1125 case SF_UPCASE:
1126 if (dataSize >= kGlobalOffset / 2)
1127 return false;
1128 UInt32 destSize = UpCaseDecode(Mem, dataSize);
1129 SetBlockSize(destSize);
1130 SetBlockPos(dataSize);
1131 break;
1132 */
1133 }
1134 return true;
1135 }
1136
1137 #endif
1138
1139 }}}
1140