1 #pragma once
2
3 #include "emulator_alu.h"
4 #include <limits>
5
6 // https://wiki.sei.cmu.edu/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow
7
8 namespace REDasm {
9
EmulatorALU(DisassemblerAPI * disassembler)10 template<typename T> EmulatorALU<T>::EmulatorALU(DisassemblerAPI *disassembler): EmulatorBase<T>(disassembler) { }
11
displacement(const Operand * op,u64 * value)12 template<typename T> bool EmulatorALU<T>::displacement(const Operand *op, u64 *value)
13 {
14 T tvalue = 0;
15
16 if(!this->displacementT(op->disp, &tvalue))
17 return false;
18
19 *value = static_cast<u64>(tvalue);
20 return true;
21 }
22
hasCarry() const23 template<typename T> bool EmulatorALU<T>::hasCarry() const { return this->flag(EmulatorALU::CarryFlag); }
24
aluOp(const InstructionPtr & instruction,size_t opdest,size_t opsrc1,size_t opsrc2)25 template<typename T> void EmulatorALU<T>::aluOp(const InstructionPtr &instruction, size_t opdest, size_t opsrc1, size_t opsrc2)
26 {
27 T src1 = 0, src2 = 0;
28
29 if(!this->readOp(instruction->op(opsrc1), &src1))
30 {
31 REDasm::problem("Cannot read operand 1 @ " + REDasm::hex(instruction->address));
32 return;
33 }
34
35 if(!this->readOp(instruction->op(opsrc2), &src2))
36 {
37 REDasm::problem("Cannot read operand 2 @ " + REDasm::hex(instruction->address));
38 return;
39 }
40
41 T dst = 0;
42
43 if(instruction->is(InstructionType::Add))
44 dst = this->aluAdd(src1, src2);
45 else if(instruction->is(InstructionType::Sub))
46 dst = this->aluSub(src1, src2);
47 else if(instruction->is(InstructionType::Mul))
48 dst = this->aluMul(src1, src2);
49 else if(instruction->is(InstructionType::Div))
50 {
51 if(!src2)
52 {
53 REDasm::problem("Division by zero @ " + REDasm::hex(instruction->address));
54 this->fail();
55 return;
56 }
57
58 dst = this->aluDiv(src1, src2);
59 }
60 else if(instruction->is(InstructionType::Mod))
61 {
62 if(!src2)
63 {
64 REDasm::problem("Module by zero @ " + REDasm::hex(instruction->address));
65 this->fail();
66 return;
67 }
68
69 dst = src1 % src2;
70 }
71 else if(instruction->is(InstructionType::And))
72 dst = src1 & src2;
73 else if(instruction->is(InstructionType::Or))
74 dst = src1 | src2;
75 else if(instruction->is(InstructionType::Xor))
76 dst = src1 ^ src2;
77 else if(instruction->is(InstructionType::Lsh))
78 {
79 if(src2 > bitscount<T>::value)
80 {
81 REDasm::problem("Invalid left shift @ " + REDasm::hex(instruction->address));
82 this->fail();
83 return;
84 }
85
86 dst = src1 << src2;
87 }
88 else if(instruction->is(InstructionType::Rsh))
89 dst = src1 >> src2;
90 else
91 {
92 this->unhandled(instruction);
93 return;
94 }
95
96 this->writeOp(instruction->op(opdest), dst);
97 }
98
aluOp(const InstructionPtr & instruction,size_t opdest,size_t opsrc)99 template<typename T> void EmulatorALU<T>::aluOp(const InstructionPtr &instruction, size_t opdest, size_t opsrc) { this->aluOp(instruction, opdest, opdest, opsrc); }
100
aluAdd(T src1,T src2)101 template<typename T> T EmulatorALU<T>::aluAdd(T src1, T src2)
102 {
103 this->carry((src1 > (std::numeric_limits<T>::max() - src2)));
104 return src1 + src2;
105 }
106
aluSub(T src1,T src2)107 template<typename T> T EmulatorALU<T>::aluSub(T src1, T src2)
108 {
109 this->carry((src1 < (std::numeric_limits<T>::min() + src2)));
110 return src1 - src2;
111 }
112
aluMul(T src1,T src2)113 template<typename T> T EmulatorALU<T>::aluMul(T src1, T src2)
114 {
115 if(!src2)
116 {
117 this->fail();
118 return 0;
119 }
120
121 this->carry((src1 > (std::numeric_limits<T>::max() / src2)));
122 return src1 * src2;
123 }
124
aluDiv(T src1,T src2)125 template<typename T> T EmulatorALU<T>::aluDiv(T src1, T src2)
126 {
127 ST ssrc1 = static_cast<ST>(src1);
128 ST ssrc2 = static_cast<ST>(src2);
129 this->carry((ssrc1 == std::numeric_limits<ST>::min()) && (ssrc2 == -1));
130 return src1 / src2;
131 }
132
carry(bool set)133 template<typename T> void EmulatorALU<T>::carry(bool set) { this->flag(EmulatorALU::CarryFlag, set); }
134
135 } // namespace REDasm
136