1 /* Copyright 2015 the unarr project authors (see AUTHORS file).
2    License: LGPLv3 */
3 
4 /* adapted from https://code.google.com/p/theunarchiver/source/browse/XADMaster/RARVirtualMachine.c */
5 
6 #include "rarvm.h"
7 #include "../common/allocator.h"
8 
9 #include <stdlib.h>
10 #include <string.h>
11 
12 typedef struct RAROpcode_s RAROpcode;
13 
14 struct RAROpcode_s {
15     uint8_t instruction;
16     uint8_t bytemode;
17     uint8_t addressingmode1;
18     uint8_t addressingmode2;
19     uint32_t value1;
20     uint32_t value2;
21 };
22 
23 struct RARProgram_s {
24     RAROpcode *opcodes;
25     uint32_t length;
26     uint32_t capacity;
27 };
28 
29 /* Program building */
30 
RARCreateProgram()31 RARProgram *RARCreateProgram()
32 {
33     return calloc(1, sizeof(RARProgram));
34 }
35 
RARDeleteProgram(RARProgram * prog)36 void RARDeleteProgram(RARProgram *prog)
37 {
38     if (prog)
39         free(prog->opcodes);
40     free(prog);
41 }
42 
RARProgramAddInstr(RARProgram * prog,uint8_t instruction,bool bytemode)43 bool RARProgramAddInstr(RARProgram *prog, uint8_t instruction, bool bytemode)
44 {
45     if (instruction >= RARNumberOfInstructions)
46         return false;
47     if (bytemode && !RARInstructionHasByteMode(instruction))
48         return false;
49     if (prog->length + 1 >= prog->capacity) {
50         /* in my small file sample, 16 is the value needed most often */
51         uint32_t newCapacity = prog->capacity ? prog->capacity * 4 : 32;
52         RAROpcode *newCodes = calloc(newCapacity, sizeof(*prog->opcodes));
53         if (!newCodes)
54             return false;
55         memcpy(newCodes, prog->opcodes, prog->capacity * sizeof(*prog->opcodes));
56         free(prog->opcodes);
57         prog->opcodes = newCodes;
58         prog->capacity = newCapacity;
59     }
60     memset(&prog->opcodes[prog->length], 0, sizeof(prog->opcodes[prog->length]));
61     prog->opcodes[prog->length].instruction = instruction;
62     if (instruction == RARMovzxInstruction || instruction == RARMovsxInstruction)
63         prog->opcodes[prog->length].bytemode = 2; /* second argument only */
64     else if (bytemode)
65         prog->opcodes[prog->length].bytemode = (1 | 2);
66     else
67         prog->opcodes[prog->length].bytemode = 0;
68     prog->length++;
69     return true;
70 }
71 
RARSetLastInstrOperands(RARProgram * prog,uint8_t addressingmode1,uint32_t value1,uint8_t addressingmode2,uint32_t value2)72 bool RARSetLastInstrOperands(RARProgram *prog, uint8_t addressingmode1, uint32_t value1, uint8_t addressingmode2, uint32_t value2)
73 {
74     RAROpcode *opcode = &prog->opcodes[prog->length - 1];
75     int numoperands;
76 
77     if (addressingmode1 >= RARNumberOfAddressingModes || addressingmode2 >= RARNumberOfAddressingModes)
78         return false;
79     if (!prog->length || opcode->addressingmode1 || opcode->value1 || opcode->addressingmode2 || opcode->value2)
80         return false;
81 
82     numoperands = NumberOfRARInstructionOperands(opcode->instruction);
83     if (numoperands == 0)
84         return true;
85 
86     if (addressingmode1 == RARImmediateAddressingMode && RARInstructionWritesFirstOperand(opcode->instruction))
87         return false;
88     opcode->addressingmode1 = addressingmode1;
89     opcode->value1 = value1;
90 
91     if (numoperands == 2) {
92         if (addressingmode2 == RARImmediateAddressingMode && RARInstructionWritesSecondOperand(opcode->instruction))
93             return false;
94         opcode->addressingmode2 = addressingmode2;
95         opcode->value2 = value2;
96     }
97 
98     return true;
99 }
100 
RARIsProgramTerminated(RARProgram * prog)101 bool RARIsProgramTerminated(RARProgram *prog)
102 {
103     return prog->length > 0 && RARInstructionIsUnconditionalJump(prog->opcodes[prog->length - 1].instruction);
104 }
105 
106 /* Execution */
107 
108 #define EXTMACRO_BEGIN do {
109 #ifdef _MSC_VER
110 #define EXTMACRO_END } __pragma(warning(push)) __pragma(warning(disable:4127)) while (0) __pragma(warning(pop))
111 #else
112 #define EXTMACRO_END } while (0)
113 #endif
114 
115 #define CarryFlag 1
116 #define ZeroFlag 2
117 #define SignFlag 0x80000000
118 
119 #define SignExtend(a) ((uint32_t)((int8_t)(a)))
120 
121 static uint32_t _RARGetOperand(RARVirtualMachine *vm, uint8_t addressingmode, uint32_t value, bool bytemode);
122 static void _RARSetOperand(RARVirtualMachine *vm, uint8_t addressingmode, uint32_t value, bool bytemode, uint32_t data);
123 
124 #define GetOperand1() _RARGetOperand(vm, opcode->addressingmode1, opcode->value1, opcode->bytemode & 1)
125 #define GetOperand2() _RARGetOperand(vm, opcode->addressingmode2, opcode->value2, opcode->bytemode & 2)
126 #define SetOperand1(data) _RARSetOperand(vm, opcode->addressingmode1, opcode->value1, opcode->bytemode & 1, data)
127 #define SetOperand2(data) _RARSetOperand(vm, opcode->addressingmode2, opcode->value2, opcode->bytemode & 2, data)
128 
129 #define SetFlagsWithCarry(res, carry) EXTMACRO_BEGIN uint32_t result = (res); flags = (result == 0 ? ZeroFlag : (result & SignFlag)) | ((carry) ? CarryFlag : 0); EXTMACRO_END
130 #define SetByteFlagsWithCarry(res, carry) EXTMACRO_BEGIN uint8_t result = (res); flags = (result == 0 ? ZeroFlag : (SignExtend(result) & SignFlag)) | ((carry) ? CarryFlag : 0); EXTMACRO_END
131 #define SetFlags(res) SetFlagsWithCarry(res, 0)
132 
133 #define SetOperand1AndFlagsWithCarry(res, carry) EXTMACRO_BEGIN uint32_t r = (res); SetFlagsWithCarry(r, carry); SetOperand1(r); EXTMACRO_END
134 #define SetOperand1AndByteFlagsWithCarry(res, carry) EXTMACRO_BEGIN uint8_t r = (res); SetByteFlagsWithCarry(r, carry); SetOperand1(r); EXTMACRO_END
135 #define SetOperand1AndFlags(res) EXTMACRO_BEGIN uint32_t r = (res); SetFlags(r); SetOperand1(r); EXTMACRO_END
136 
137 #define NextInstruction() { opcode++; continue; }
138 #define Jump(offs) { uint32_t o = (offs); if (o >= prog->length) return false; opcode = &prog->opcodes[o]; continue; }
139 
RARExecuteProgram(RARVirtualMachine * vm,RARProgram * prog)140 bool RARExecuteProgram(RARVirtualMachine *vm, RARProgram *prog)
141 {
142     RAROpcode *opcode = prog->opcodes;
143     uint32_t flags = 0;
144     uint32_t op1, op2, carry, i;
145     uint32_t counter = 0;
146 
147     if (!RARIsProgramTerminated(prog))
148         return false;
149 
150     while ((uint32_t)(opcode - prog->opcodes) < prog->length && counter++ < RARRuntimeMaxInstructions) {
151         switch (opcode->instruction) {
152         case RARMovInstruction:
153             SetOperand1(GetOperand2());
154             NextInstruction();
155 
156         case RARCmpInstruction:
157             op1 = GetOperand1();
158             SetFlagsWithCarry(op1 - GetOperand2(), result > op1);
159             NextInstruction();
160 
161         case RARAddInstruction:
162             op1 = GetOperand1();
163             if (opcode->bytemode)
164                 SetOperand1AndByteFlagsWithCarry((op1 + GetOperand2()) & 0xFF, result < op1);
165             else
166                 SetOperand1AndFlagsWithCarry(op1 + GetOperand2(), result < op1);
167             NextInstruction();
168 
169         case RARSubInstruction:
170             op1 = GetOperand1();
171 #if 0 /* apparently not correctly implemented in the RAR VM */
172             if (opcode->bytemode)
173                 SetOperand1AndByteFlagsWithCarry((op1 - GetOperand2()) & 0xFF, result > op1);
174             else
175 #endif
176             SetOperand1AndFlagsWithCarry(op1 - GetOperand2(), result > op1);
177             NextInstruction();
178 
179         case RARJzInstruction:
180             if ((flags & ZeroFlag))
181                 Jump(GetOperand1());
182             NextInstruction();
183 
184         case RARJnzInstruction:
185             if (!(flags & ZeroFlag))
186                 Jump(GetOperand1());
187             NextInstruction();
188 
189         case RARIncInstruction:
190             if (opcode->bytemode)
191                 SetOperand1AndFlags((GetOperand1() + 1) & 0xFF);
192             else
193                 SetOperand1AndFlags(GetOperand1() + 1);
194             NextInstruction();
195 
196         case RARDecInstruction:
197             if (opcode->bytemode)
198                 SetOperand1AndFlags((GetOperand1() - 1) & 0xFF);
199             else
200                 SetOperand1AndFlags(GetOperand1() - 1);
201             NextInstruction();
202 
203         case RARJmpInstruction:
204             Jump(GetOperand1());
205 
206         case RARXorInstruction:
207             SetOperand1AndFlags(GetOperand1() ^ GetOperand2());
208             NextInstruction();
209 
210         case RARAndInstruction:
211             SetOperand1AndFlags(GetOperand1() & GetOperand2());
212             NextInstruction();
213 
214         case RAROrInstruction:
215             SetOperand1AndFlags(GetOperand1() | GetOperand2());
216             NextInstruction();
217 
218         case RARTestInstruction:
219             SetFlags(GetOperand1() & GetOperand2());
220             NextInstruction();
221 
222         case RARJsInstruction:
223             if ((flags & SignFlag))
224                 Jump(GetOperand1());
225             NextInstruction();
226 
227         case RARJnsInstruction:
228             if (!(flags & SignFlag))
229                 Jump(GetOperand1());
230             NextInstruction();
231 
232         case RARJbInstruction:
233             if ((flags & CarryFlag))
234                 Jump(GetOperand1());
235             NextInstruction();
236 
237         case RARJbeInstruction:
238             if ((flags & (CarryFlag | ZeroFlag)))
239                 Jump(GetOperand1());
240             NextInstruction();
241 
242         case RARJaInstruction:
243             if (!(flags & (CarryFlag | ZeroFlag)))
244                 Jump(GetOperand1());
245             NextInstruction();
246 
247         case RARJaeInstruction:
248             if (!(flags & CarryFlag))
249                 Jump(GetOperand1());
250             NextInstruction();
251 
252         case RARPushInstruction:
253             vm->registers[7] -= 4;
254             RARVirtualMachineWrite32(vm, vm->registers[7], GetOperand1());
255             NextInstruction();
256 
257         case RARPopInstruction:
258             SetOperand1(RARVirtualMachineRead32(vm, vm->registers[7]));
259             vm->registers[7] += 4;
260             NextInstruction();
261 
262         case RARCallInstruction:
263             vm->registers[7] -= 4;
264             RARVirtualMachineWrite32(vm, vm->registers[7], (uint32_t)(opcode - prog->opcodes + 1));
265             Jump(GetOperand1());
266 
267         case RARRetInstruction:
268             if (vm->registers[7] >= RARProgramMemorySize)
269                 return true;
270             i = RARVirtualMachineRead32(vm, vm->registers[7]);
271             vm->registers[7] += 4;
272             Jump(i);
273 
274         case RARNotInstruction:
275             SetOperand1(~GetOperand1());
276             NextInstruction();
277 
278         case RARShlInstruction:
279             op1 = GetOperand1();
280             op2 = GetOperand2();
281             SetOperand1AndFlagsWithCarry(op1 << op2, ((op1 << (op2 - 1)) & 0x80000000) != 0);
282             NextInstruction();
283 
284         case RARShrInstruction:
285             op1 = GetOperand1();
286             op2 = GetOperand2();
287             SetOperand1AndFlagsWithCarry(op1 >> op2, ((op1 >> (op2 - 1)) & 1) != 0);
288             NextInstruction();
289 
290         case RARSarInstruction:
291             op1 = GetOperand1();
292             op2 = GetOperand2();
293             SetOperand1AndFlagsWithCarry(((int32_t)op1) >> op2, ((op1 >> (op2 - 1)) & 1) != 0);
294             NextInstruction();
295 
296         case RARNegInstruction:
297             SetOperand1AndFlagsWithCarry(-(int32_t)GetOperand1(), result != 0);
298             NextInstruction();
299 
300         case RARPushaInstruction:
301             vm->registers[7] -= 32;
302             for (i = 0; i < 8; i++)
303                 RARVirtualMachineWrite32(vm, vm->registers[7] + (7 - i) * 4, vm->registers[i]);
304             NextInstruction();
305 
306         case RARPopaInstruction:
307             for (i = 0; i < 8; i++)
308                 vm->registers[i] = RARVirtualMachineRead32(vm, vm->registers[7] + (7 - i) * 4);
309             vm->registers[7] += 32;
310             NextInstruction();
311 
312         case RARPushfInstruction:
313             vm->registers[7] -= 4;
314             RARVirtualMachineWrite32(vm, vm->registers[7], flags);
315             NextInstruction();
316 
317         case RARPopfInstruction:
318             flags = RARVirtualMachineRead32(vm, vm->registers[7]);
319             vm->registers[7] += 4;
320             NextInstruction();
321 
322         case RARMovzxInstruction:
323             SetOperand1(GetOperand2());
324             NextInstruction();
325 
326         case RARMovsxInstruction:
327             SetOperand1(SignExtend(GetOperand2()));
328             NextInstruction();
329 
330         case RARXchgInstruction:
331             op1 = GetOperand1();
332             op2 = GetOperand2();
333             SetOperand1(op2);
334             SetOperand2(op1);
335             NextInstruction();
336 
337         case RARMulInstruction:
338             SetOperand1(GetOperand1() * GetOperand2());
339             NextInstruction();
340 
341         case RARDivInstruction:
342             op2 = GetOperand2();
343             if (op2 != 0)
344                 SetOperand1(GetOperand1() / op2);
345             NextInstruction();
346 
347         case RARAdcInstruction:
348             op1 = GetOperand1();
349             carry = (flags & CarryFlag);
350             if (opcode->bytemode)
351                 SetOperand1AndFlagsWithCarry((op1 + GetOperand2() + carry) & 0xFF, result < op1 || (result == op1 && carry)); /* does not correctly set sign bit */
352             else
353                 SetOperand1AndFlagsWithCarry(op1 + GetOperand2() + carry, result < op1 || (result == op1 && carry));
354             NextInstruction();
355 
356         case RARSbbInstruction:
357             op1 = GetOperand1();
358             carry = (flags & CarryFlag);
359             if (opcode->bytemode)
360                 SetOperand1AndFlagsWithCarry((op1 - GetOperand2() - carry) & 0xFF, result > op1 || (result == op1 && carry)); /* does not correctly set sign bit */
361             else
362                 SetOperand1AndFlagsWithCarry(op1 - GetOperand2() - carry, result > op1 || (result == op1 && carry));
363             NextInstruction();
364 
365         case RARPrintInstruction:
366             /* TODO: ??? */
367             NextInstruction();
368         }
369     }
370 
371     return false;
372 }
373 
374 /* Memory and register access */
375 
_RARRead32(const uint8_t * b)376 static uint32_t _RARRead32(const uint8_t *b)
377 {
378     return ((uint32_t)b[3] << 24) | ((uint32_t)b[2] << 16) | ((uint32_t)b[1] << 8) | (uint32_t)b[0];
379 }
380 
_RARWrite32(uint8_t * b,uint32_t n)381 static void _RARWrite32(uint8_t *b, uint32_t n)
382 {
383     b[3] = (n >> 24) & 0xFF;
384     b[2] = (n >> 16) & 0xFF;
385     b[1] = (n >> 8) & 0xFF;
386     b[0] = n & 0xFF;
387 }
388 
RARSetVirtualMachineRegisters(RARVirtualMachine * vm,uint32_t registers[8])389 void RARSetVirtualMachineRegisters(RARVirtualMachine *vm, uint32_t registers[8])
390 {
391     if (registers)
392         memcpy(vm->registers, registers, sizeof(vm->registers));
393     else
394         memset(vm->registers, 0, sizeof(vm->registers));
395 }
396 
RARVirtualMachineRead32(RARVirtualMachine * vm,uint32_t address)397 uint32_t RARVirtualMachineRead32(RARVirtualMachine *vm, uint32_t address)
398 {
399     return _RARRead32(&vm->memory[address & RARProgramMemoryMask]);
400 }
401 
RARVirtualMachineWrite32(RARVirtualMachine * vm,uint32_t address,uint32_t val)402 void RARVirtualMachineWrite32(RARVirtualMachine *vm, uint32_t address, uint32_t val)
403 {
404     _RARWrite32(&vm->memory[address & RARProgramMemoryMask], val);
405 }
406 
RARVirtualMachineRead8(RARVirtualMachine * vm,uint32_t address)407 uint8_t RARVirtualMachineRead8(RARVirtualMachine *vm, uint32_t address)
408 {
409     return vm->memory[address & RARProgramMemoryMask];
410 }
411 
RARVirtualMachineWrite8(RARVirtualMachine * vm,uint32_t address,uint8_t val)412 void RARVirtualMachineWrite8(RARVirtualMachine *vm, uint32_t address, uint8_t val)
413 {
414     vm->memory[address & RARProgramMemoryMask] = val;
415 }
416 
_RARGetOperand(RARVirtualMachine * vm,uint8_t addressingmode,uint32_t value,bool bytemode)417 static uint32_t _RARGetOperand(RARVirtualMachine *vm, uint8_t addressingmode, uint32_t value, bool bytemode)
418 {
419     if (RARRegisterAddressingMode(0) <= addressingmode && addressingmode <= RARRegisterAddressingMode(7)) {
420         uint32_t result = vm->registers[addressingmode % 8];
421         if (bytemode)
422             result = result & 0xFF;
423         return result;
424     }
425     if (RARRegisterIndirectAddressingMode(0) <= addressingmode && addressingmode <= RARRegisterIndirectAddressingMode(7)) {
426         if (bytemode)
427             return RARVirtualMachineRead8(vm, vm->registers[addressingmode % 8]);
428         return RARVirtualMachineRead32(vm, vm->registers[addressingmode % 8]);
429     }
430     if (RARIndexedAbsoluteAddressingMode(0) <= addressingmode && addressingmode <= RARIndexedAbsoluteAddressingMode(7)) {
431         if (bytemode)
432             return RARVirtualMachineRead8(vm, value + vm->registers[addressingmode % 8]);
433         return RARVirtualMachineRead32(vm, value + vm->registers[addressingmode % 8]);
434     }
435     if (addressingmode == RARAbsoluteAddressingMode) {
436         if (bytemode)
437             return RARVirtualMachineRead8(vm, value);
438         return RARVirtualMachineRead32(vm, value);
439     }
440     /* if (addressingmode == RARImmediateAddressingMode) */
441     return value;
442 }
443 
_RARSetOperand(RARVirtualMachine * vm,uint8_t addressingmode,uint32_t value,bool bytemode,uint32_t data)444 static void _RARSetOperand(RARVirtualMachine *vm, uint8_t addressingmode, uint32_t value, bool bytemode, uint32_t data)
445 {
446     if (RARRegisterAddressingMode(0) <= addressingmode && addressingmode <= RARRegisterAddressingMode(7)) {
447         if (bytemode)
448             data = data & 0xFF;
449         vm->registers[addressingmode % 8] = data;
450     }
451     else if (RARRegisterIndirectAddressingMode(0) <= addressingmode && addressingmode <= RARRegisterIndirectAddressingMode(7)) {
452         if (bytemode)
453             RARVirtualMachineWrite8(vm, vm->registers[addressingmode % 8], (uint8_t)data);
454         else
455             RARVirtualMachineWrite32(vm, vm->registers[addressingmode % 8], data);
456     }
457     else if (RARIndexedAbsoluteAddressingMode(0) <= addressingmode && addressingmode <= RARIndexedAbsoluteAddressingMode(7)) {
458         if (bytemode)
459             RARVirtualMachineWrite8(vm, value + vm->registers[addressingmode % 8], (uint8_t)data);
460         else
461             RARVirtualMachineWrite32(vm, value + vm->registers[addressingmode % 8], data);
462     }
463     else if (addressingmode == RARAbsoluteAddressingMode) {
464         if (bytemode)
465             RARVirtualMachineWrite8(vm, value, (uint8_t)data);
466         else
467             RARVirtualMachineWrite32(vm, value, data);
468     }
469 }
470 
471 /* Instruction properties */
472 
473 #define RAR0OperandsFlag 0
474 #define RAR1OperandFlag 1
475 #define RAR2OperandsFlag 2
476 #define RAROperandsFlag 3
477 #define RARHasByteModeFlag 4
478 #define RARIsUnconditionalJumpFlag 8
479 #define RARIsRelativeJumpFlag 16
480 #define RARWritesFirstOperandFlag 32
481 #define RARWritesSecondOperandFlag 64
482 #define RARReadsStatusFlag 128
483 #define RARWritesStatusFlag 256
484 
485 static const int InstructionFlags[RARNumberOfInstructions] = {
486     /*RARMovInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag,
487     /*RARCmpInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesStatusFlag,
488     /*RARAddInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag,
489     /*RARSubInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag,
490     /*RARJzInstruction*/ RAR1OperandFlag | RARIsUnconditionalJumpFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag,
491     /*RARJnzInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag,
492     /*RARIncInstruction*/ RAR1OperandFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag,
493     /*RARDecInstruction*/ RAR1OperandFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag,
494     /*RARJmpInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag,
495     /*RARXorInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag,
496     /*RARAndInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag,
497     /*RAROrInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag,
498     /*RARTestInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesStatusFlag,
499     /*RARJsInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag,
500     /*RARJnsInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag,
501     /*RARJbInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag,
502     /*RARJbeInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag,
503     /*RARJaInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag,
504     /*RARJaeInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag,
505     /*RARPushInstruction*/ RAR1OperandFlag,
506     /*RARPopInstruction*/ RAR1OperandFlag,
507     /*RARCallInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag,
508     /*RARRetInstruction*/ RAR0OperandsFlag | RARIsUnconditionalJumpFlag,
509     /*RARNotInstruction*/ RAR1OperandFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag,
510     /*RARShlInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag,
511     /*RARShrInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag,
512     /*RARSarInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag,
513     /*RARNegInstruction*/ RAR1OperandFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag,
514     /*RARPushaInstruction*/ RAR0OperandsFlag,
515     /*RARPopaInstruction*/ RAR0OperandsFlag,
516     /*RARPushfInstruction*/ RAR0OperandsFlag | RARReadsStatusFlag,
517     /*RARPopfInstruction*/ RAR0OperandsFlag | RARWritesStatusFlag,
518     /*RARMovzxInstruction*/ RAR2OperandsFlag | RARWritesFirstOperandFlag,
519     /*RARMovsxInstruction*/ RAR2OperandsFlag | RARWritesFirstOperandFlag,
520     /*RARXchgInstruction*/ RAR2OperandsFlag | RARWritesFirstOperandFlag | RARWritesSecondOperandFlag | RARHasByteModeFlag,
521     /*RARMulInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag,
522     /*RARDivInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag,
523     /*RARAdcInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARReadsStatusFlag | RARWritesStatusFlag,
524     /*RARSbbInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARReadsStatusFlag | RARWritesStatusFlag,
525     /*RARPrintInstruction*/ RAR0OperandsFlag
526 };
527 
NumberOfRARInstructionOperands(uint8_t instruction)528 int NumberOfRARInstructionOperands(uint8_t instruction)
529 {
530     if (instruction >= RARNumberOfInstructions)
531         return 0;
532     return InstructionFlags[instruction] & RAROperandsFlag;
533 }
534 
RARInstructionHasByteMode(uint8_t instruction)535 bool RARInstructionHasByteMode(uint8_t instruction)
536 {
537     if (instruction >= RARNumberOfInstructions)
538         return false;
539     return (InstructionFlags[instruction] & RARHasByteModeFlag)!=0;
540 }
541 
RARInstructionIsUnconditionalJump(uint8_t instruction)542 bool RARInstructionIsUnconditionalJump(uint8_t instruction)
543 {
544     if (instruction >= RARNumberOfInstructions)
545         return false;
546     return (InstructionFlags[instruction] & RARIsUnconditionalJumpFlag) != 0;
547 }
548 
RARInstructionIsRelativeJump(uint8_t instruction)549 bool RARInstructionIsRelativeJump(uint8_t instruction)
550 {
551     if (instruction >= RARNumberOfInstructions)
552         return false;
553     return (InstructionFlags[instruction] & RARIsRelativeJumpFlag) != 0;
554 }
555 
RARInstructionWritesFirstOperand(uint8_t instruction)556 bool RARInstructionWritesFirstOperand(uint8_t instruction)
557 {
558     if (instruction >= RARNumberOfInstructions)
559         return false;
560     return (InstructionFlags[instruction] & RARWritesFirstOperandFlag) != 0;
561 }
562 
RARInstructionWritesSecondOperand(uint8_t instruction)563 bool RARInstructionWritesSecondOperand(uint8_t instruction)
564 {
565     if (instruction >= RARNumberOfInstructions)
566         return false;
567     return (InstructionFlags[instruction] & RARWritesSecondOperandFlag) != 0;
568 }
569 
570 /* Program debugging */
571 
572 #ifndef NDEBUG
573 #include <stdio.h>
574 
RARPrintOperand(uint8_t addressingmode,uint32_t value)575 static void RARPrintOperand(uint8_t addressingmode, uint32_t value)
576 {
577     if (RARRegisterAddressingMode(0) <= addressingmode && addressingmode <= RARRegisterAddressingMode(7))
578         printf("r%d", addressingmode % 8);
579     else if (RARRegisterIndirectAddressingMode(0) <= addressingmode && addressingmode <= RARRegisterIndirectAddressingMode(7))
580         printf("@(r%d)", addressingmode % 8);
581     else if (RARIndexedAbsoluteAddressingMode(0) <= addressingmode && addressingmode <= RARIndexedAbsoluteAddressingMode(7))
582         printf("@(r%d+$%02x)", addressingmode % 8, value);
583     else if (addressingmode == RARAbsoluteAddressingMode)
584         printf("@($%02x)", value);
585     else if (addressingmode == RARImmediateAddressingMode)
586         printf("$%02x", value);
587 }
588 
RARPrintProgram(RARProgram * prog)589 void RARPrintProgram(RARProgram *prog)
590 {
591     static const char *instructionNames[RARNumberOfInstructions] = {
592         "Mov", "Cmp", "Add", "Sub", "Jz", "Jnz", "Inc", "Dec", "Jmp", "Xor",
593         "And", "Or", "Test", "Js", "Jns", "Jb", "Jbe", "Ja", "Jae", "Push",
594         "Pop", "Call", "Ret", "Not", "Shl", "Shr", "Sar", "Neg", "Pusha", "Popa",
595         "Pushf", "Popf", "Movzx", "Movsx", "Xchg", "Mul", "Div", "Adc", "Sbb", "Print",
596     };
597 
598     uint32_t i;
599     for (i = 0; i < prog->length; i++) {
600         RAROpcode *opcode = &prog->opcodes[i];
601         int numoperands = NumberOfRARInstructionOperands(opcode->instruction);
602         printf("  %02x: %s", i, instructionNames[opcode->instruction]);
603         if (opcode->bytemode)
604             printf("B");
605         if (numoperands >= 1) {
606             printf(" ");
607             RARPrintOperand(opcode->addressingmode1, opcode->value1);
608         }
609         if (numoperands == 2) {
610             printf(", ");
611             RARPrintOperand(opcode->addressingmode2, opcode->value2);
612         }
613         printf("\n");
614     }
615 }
616 #endif
617