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