From 90c2782d0b78d64a19e7236c7dd6d8cc7a2e8396 Mon Sep 17 00:00:00 2001 From: Dennis Brentjes Date: Sat, 16 Jun 2018 19:26:59 +0200 Subject: Rewrites the binary operation function to have code reuse between unary and binary operations. --- emulate/emulator.cpp | 233 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 228 insertions(+), 5 deletions(-) (limited to 'emulate/emulator.cpp') diff --git a/emulate/emulator.cpp b/emulate/emulator.cpp index 669684f..d30081e 100644 --- a/emulate/emulator.cpp +++ b/emulate/emulator.cpp @@ -35,12 +35,190 @@ Emulator::ValueType Emulator::extract_immediate_of_size(int size, _DInst inst) { } } +std::unique_ptr Emulator::get_first_operand(_DInst inst) { + _Operand dest_op = inst.ops[0]; + std::unique_ptr dest; + + switch(dest_op.type) { + case O_REG: { + dest = std::make_unique(register_getters.at(dest_op.index)()); + break; + } + case O_MEM: { + throw UnhandledInstruction(); + break; + } + case O_SMEM: { + auto segment = register_getters.at(SEGMENT_GET(inst.segment))(); + auto segment_offset = ldt[boost::apply_visitor(return_visitor(), segment) >> 3].offset; + auto register_contents = register_getters.at(dest_op.index)(); + int32_t offset = boost::apply_visitor(return_visitor(), register_contents) + inst.disp; + std::cout << segment_offset << std::endl << offset << std::endl << inst.disp << std::endl; + std::cout << segment_offset + offset + inst.disp << std::endl; + auto memory_offset = segment_offset + offset + inst.disp; + switch(dest_op.size) { + case 8: { + dest = std::make_unique(*reinterpret_cast(&memory[memory_offset])); + break; + } + case 16: { + dest = std::make_unique(*reinterpret_cast(&memory[memory_offset])); + break; + } + case 32: { + dest = std::make_unique(*reinterpret_cast(&memory[memory_offset])); + break; + } + default: { + throw UnhandledInstruction(); + } + } + + break; + } + case O_DISP: { + auto segment = register_getters.at(SEGMENT_GET(inst.segment))(); + auto segment_offset = ldt[boost::apply_visitor(return_visitor(), segment) >> 3].offset; + switch(dest_op.size) { + case 8: { + dest = std::make_unique(*reinterpret_cast(&memory[segment_offset + inst.disp])); + break; + } + case 16: { + dest = std::make_unique(*reinterpret_cast(&memory[segment_offset + inst.disp])); + break; + } + case 32: { + dest = std::make_unique(*reinterpret_cast(&memory[segment_offset + inst.disp])); + break; + } + default: { + throw UnhandledInstruction(); + } + } + break; + } + default: { + throw UnhandledInstruction(); + } + } + return dest;; +} + +Emulator::ValueType Emulator::get_second_operand(_DInst inst, RefValueType dest) { + ValueType src; + _Operand src_op = inst.ops[1]; + + switch(src_op.type) { + case O_REG: { + auto x = register_getters.at(src_op.index)(); + src = boost::apply_visitor(to_target_type(), dest, x); + break; + } + case O_IMM: { + //Do not rely on the imm size as we need to sign extend to dest size. + src = extract_immediate_of_size(boost::apply_visitor(dest_size(), dest), inst); + break; + } + case O_DISP: { + auto segment = register_getters.at(SEGMENT_GET(inst.segment))(); + auto segment_offset = ldt[boost::apply_visitor(return_visitor(), segment) >> 3].offset; + switch(boost::apply_visitor(dest_size(), dest)) { + case 8: { + if(segment_offset + inst.disp > memory.size()) { + std::cerr << "Warning reading outside of memory region" << std::endl; + src = static_cast(0); + } else { + src = *reinterpret_cast(&memory[segment_offset + inst.disp]); + } + break; + } + case 16: { + if(segment_offset + inst.disp + 1 > memory.size()) { + std::cerr << "Warning reading outside of memory region" << std::endl; + src = static_cast(0); + } else { + src = *reinterpret_cast(&memory[segment_offset + inst.disp]); + } + break; + } + case 32: { + if(segment_offset + inst.disp + 3 > memory.size()) { + std::cerr << "Warning reading outside of memory region" << std::endl; + src = static_cast(0); + } else { + src = *reinterpret_cast(&memory[segment_offset + inst.disp]); + } + break; + } + default: { + throw UnhandledInstruction(); + } + } + break; + } + case O_SMEM: { + auto segment = register_getters.at(SEGMENT_GET(inst.segment))(); + auto segment_offset = ldt[boost::apply_visitor(return_visitor(), segment) >> 3].offset; + auto register_contents = register_getters.at(src_op.index)(); + int32_t offset = boost::apply_visitor(return_visitor(), register_contents) + inst.disp; + std::cout << segment_offset << std::endl << offset << std::endl << inst.disp << std::endl; + std::cout << segment_offset + offset + inst.disp << std::endl; + auto memory_offset = segment_offset + offset + inst.disp; + switch(src_op.size) { + case 8: { + src = *reinterpret_cast(&memory[memory_offset]); + break; + } + case 16: { + src = *reinterpret_cast(&memory[memory_offset]); + break; + } + case 32: { + src = *reinterpret_cast(&memory[memory_offset]); + break; + } + case 0: { + assert(inst.opcode == I_LEA); + switch(boost::apply_visitor(dest_size(), dest)) { + case 8: { + throw UnrecognizedInstruction(); + } + case 16: { + src = static_cast(memory_offset); + break; + } + case 32: { + src = static_cast(memory_offset); + break; + } + default: { + throw UnrecognizedInstruction(); + } + } + + break; + } + default: { + throw UnhandledInstruction(); + } + } + break; + } + default: { + throw UnhandledInstruction(); + + } + } + return src; +} + template struct op : public boost::static_visitor { CpuState& cpu; op(CpuState& cpu) - : cpu(cpu) + : cpu(cpu) {} }; @@ -54,6 +232,11 @@ struct binary_op : public op { } }; +template +struct unary_op : public op { + using op::op; +}; + struct and_ : public binary_op { using binary_op::operator(); using binary_op::binary_op; @@ -80,10 +263,7 @@ struct mov : public binary_op { template void operator()(T& lh, T const& rh) const { - std::cout << unsigned(lh) << std::endl; - std::cout << unsigned(rh) << std::endl; lh = rh; - std::cout << unsigned(lh) << std::endl; } }; @@ -146,13 +326,32 @@ struct cmp : public binary_op { cpu.cf() = !(static_cast(std::numeric_limits::min()) & lh) && (static_cast(std::numeric_limits::min()) & rh); T result = lh - rh; - + cpu.sf() = static_cast(std::numeric_limits::min()) & result; cpu.zf() = result == 0; cpu.pf() = ((result & 1) + (result >> 1 & 1) + (result >> 2 & 1) + (result >> 3 & 1) + (result >> 4 & 1) + (result >> 5 & 1) + (result >> 6 & 1) + (result >> 7 & 1) % 2) + 1; } }; +struct lea : public binary_op { + using binary_op::operator(); + using binary_op::binary_op; + + template + void operator()(T& lh, T const& rh) const { + lh = rh; + } +}; + +struct dec : public unary_op { + using unary_op::unary_op; + + template + void operator()(T& op) const { + op--; + } +}; + uint32_t Emulator::get_jmp_target(_DInst inst) { if(inst.ops[0].type == O_PC || inst.ops[0].type == O_PTR || inst.ops[0].type == O_DISP) { return INSTRUCTION_GET_TARGET(&inst); @@ -270,6 +469,27 @@ void Emulator::handle_I_CLD(_DInst inst) cpu.df() = 0; } +void Emulator::handle_I_SCAS(_DInst inst) +{ + if(FLAG_GET_PREFIX(inst.flags) == FLAG_REP) { + while(cpu.ecx() != 0 && cpu.zf() != 0) { + throw UnhandledInstruction(); + } + } else { + throw UnhandledInstruction(); + } +} + +void Emulator::handle_I_LEA(_DInst inst) +{ + handle_binary(inst); +} + +void Emulator::handle_I_DEC(_DInst inst) +{ + handle_unary(inst); +} + void Emulator::int_0x21() { switch(cpu.ah()) { //Dos Version @@ -347,6 +567,9 @@ Emulator::Emulator(binparse::Offset32 init_eip, binparse::Offset32 init_esp, std REGISTER_HANDLER(I_ADD ); REGISTER_HANDLER(I_PUSH); REGISTER_HANDLER(I_CLD ); + REGISTER_HANDLER(I_SCAS); + REGISTER_HANDLER(I_LEA ); + REGISTER_HANDLER(I_DEC ); #undef REGISTER_HANDLER -- cgit v1.2.3-70-g09d2