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