import ctypes
import enum
import logging
import sys
from six import add_metaclass, iteritems, string_types
from six.moves import range
from functools import partial
from collections import OrderedDict
from .registers import Registers, REGISTER_NAMES
from ..mm import u32_t, i32_t, UINT16_FMT, UINT32_FMT
from ..util import LoggingCapable
from ..errors import EncodingLargeValueError, UnalignedJumpTargetError, InvalidOpcodeError, DivideByZeroError, InvalidInstructionSetError, OperandMismatchError, PrivilegedInstructionError
[docs]def UINT20_FMT(i):
return '0x%05X' % (i & 0xFFFFF)
[docs]def encoding_to_u32(inst):
return ctypes.cast(ctypes.byref(inst), ctypes.POINTER(u32_t)).contents.value
[docs]def IE_OPCODE():
return ('opcode', u32_t, 6)
[docs]def IE_FLAG(n):
return (n, u32_t, 1)
[docs]def IE_REG(n):
return (n, u32_t, 5)
[docs]def IE_IMM(n, l):
return (n, u32_t, l)
[docs]class Encoding(ctypes.LittleEndianStructure):
@staticmethod
@staticmethod
[docs] def repr(inst, fields):
d = OrderedDict()
fields.insert(0, ('opcode', '%02d'))
for field, fmt in fields:
d[field] = fmt % getattr(inst, field)
if hasattr(inst, 'refers_to'):
d['refers_to'] = str(getattr(inst, 'refers_to'))
return '<%s: %s>' % (inst.__class__.__name__, ', '.join(['%s=%s' % (k, v) for k, v in iteritems(d)]))
[docs]class EncodingR(ctypes.LittleEndianStructure):
_pack_ = 0
_fields_ = [
IE_OPCODE(), # 0
IE_REG('reg1'), # 6
IE_REG('reg2'), # 11
IE_FLAG('immediate_flag'), # 16
IE_IMM('immediate', 15), # 17
]
@staticmethod
[docs] def fill_reloc_slot(inst, slot):
logging.getLogger().debug('fill_reloc_slot: inst=%s, slot=%s', inst, slot)
slot.patch_offset = 17
slot.patch_size = 15
@staticmethod
def __repr__(self):
return Encoding.repr(self, [('reg1', '%02d'), ('reg2', '%02d'), ('immediate_flag', '%d'), ('immediate', '0x%04X')])
[docs]class EncodingC(ctypes.LittleEndianStructure):
_pack_ = 0
_fields_ = [
IE_OPCODE(), # 0
IE_REG('reg'), # 6
IE_IMM('flag', 3), # 11
IE_FLAG('value'), # 14
IE_FLAG('immediate_flag'), # 25
IE_IMM('immediate', 16) # 16
]
@staticmethod
[docs] def fill_reloc_slot(inst, slot):
logging.getLogger().debug('fill_reloc_slot: inst=%s, slot=%s', inst, slot)
slot.patch_offset = 16
slot.patch_size = 16
@staticmethod
def __repr__(self):
return Encoding.repr(self, [('reg', '%02d'), ('flag', '%02d'), ('value', '%d'), ('immediate_flag', '%d'), ('immediate', '0x%04X')])
[docs]class EncodingS(ctypes.LittleEndianStructure):
_pack_ = 0
_fields_ = [
IE_OPCODE(), # 0
IE_REG('reg1'), # 6
IE_REG('reg2'), # 11
IE_IMM('flag', 3), # 16
IE_FLAG('value'), # 19
IE_FLAG('immediate_flag'), # 20
IE_IMM('immediate', 11) # 21
]
@staticmethod
[docs] def fill_reloc_slot(inst, slot):
logging.getLogger().debug('fill_reloc_slot: inst=%s, slot=%s', inst, slot)
slot.patch_offset = 21
slot.patch_size = 11
@staticmethod
def __repr__(self):
return Encoding.repr(self, [('reg1', '%02d'), ('reg2', '%02d'), ('flag', '%02d'), ('value', '%d'), ('immediate_flag', '%d'), ('immediate', '0x%04X')])
[docs]class EncodingI(ctypes.LittleEndianStructure):
_pack_ = 0
_fields_ = [
IE_OPCODE(), # 0
IE_REG('reg'), # 6
IE_FLAG('immediate_flag'), # 11
IE_IMM('immediate', 20), # 12
]
@staticmethod
[docs] def fill_reloc_slot(inst, slot):
logging.getLogger().debug('fill_reloc_slot: inst=%s, slot=%s', inst, slot)
slot.patch_offset = 12
slot.patch_size = 20
@staticmethod
def __repr__(self):
return Encoding.repr(self, [('reg', '%02d'), ('immediate_flag', '%d'), ('immediate', '0x%04X')])
[docs]class EncodingA(ctypes.LittleEndianStructure):
_pack_ = 0
_fields_ = [
IE_OPCODE(), # 0
IE_REG('reg1'), # 6
IE_REG('reg2'), # 11
IE_REG('reg3') # 16
]
def __repr__(self):
return Encoding.repr(self, [('reg1', '%02d'), ('reg2', '%02d'), ('reg3', '%02d')])
[docs]class EncodingContext(LoggingCapable, object):
def __init__(self, logger):
super(EncodingContext, self).__init__(logger)
if hasattr(sys, 'pypy_version_info'):
self.u32_to_encoding = self._u32_to_encoding_pypy
else:
self.u32_to_encoding = self._u32_to_encoding_python
[docs] def _u32_to_encoding_pypy(self, u, encoding):
class _Cast(ctypes.Union):
_pack_ = 0
_fields_ = [
('overall', u32_t),
('encoding', encoding)
]
caster = _Cast()
caster.overall = u32_t(u).value
return caster.encoding
[docs] def _u32_to_encoding_python(self, u, encoding):
u = u32_t(u)
e = encoding()
ctypes.cast(ctypes.byref(e), ctypes.POINTER(encoding))[0] = ctypes.cast(ctypes.byref(u), ctypes.POINTER(encoding)).contents
return e
[docs] def encode(self, inst, field, size, value, raise_on_large_value = False):
self.DEBUG('encode: inst=%s, field=%s, size=%s, value=%s, raise_on_large_value=%s', inst, field, size, value, raise_on_large_value)
setattr(inst, field, value)
self.DEBUG('encode: inst=%s', inst)
if value >= 2 ** size:
e = buffer.get_error(EncodingLargeValueError, 'inst=%s, field=%s, size=%s, value=%s' % (inst, field, size, UINT32_FMT(value)))
if raise_on_large_value is True:
raise e
e.log(self.WARN)
[docs] def decode(self, instr_set, inst, core = None):
self.DEBUG('%s.decode: inst=%s, core=%s', self.__class__.__name__, inst, core)
opcode = inst & 0x3F
if opcode not in instr_set.opcode_desc_map:
raise InvalidOpcodeError(opcode, core = core)
return self.u32_to_encoding(inst, instr_set.opcode_encoding_map[opcode]), instr_set.opcode_desc_map[opcode], opcode
[docs]class Descriptor(object):
mnemonic = None
opcode = None
operands = None
# this is a default encoding, and by the way it silents Codacy's warning
encoding = EncodingR
relative_address = False
inst_aligned = False
def __init__(self, instruction_set):
super(Descriptor, self).__init__()
self.instruction_set = instruction_set
self.instruction_set.instructions.append(self)
self._expand_operands()
[docs] def _expand_operands(self):
if isinstance(self.__class__.operands, list):
return
self.__class__.operands = [ot.strip() for ot in self.operands.split(',')] if self.operands is not None else []
self.operands = self.__class__.operands
#
# Execution
#
@staticmethod
[docs] def jit(core, inst):
return None
@staticmethod
[docs] def execute(core, inst):
raise NotImplementedError('%s does not implement execute method' % inst.opcode)
#
# Encoding
#
@staticmethod
[docs] def assemble_operands(ctx, inst, operands):
pass
@staticmethod
[docs] def fill_reloc_slot(inst, slot):
inst.fill_reloc_slot(inst, slot)
@staticmethod
[docs] def disassemble_operands(logger, inst):
return []
@classmethod
[docs] def disassemble_mnemonic(cls, inst):
return cls.mnemonic
@staticmethod
[docs] def _match_operand_type(allowed, operand):
from ..asm.ast import RegisterOperand, ImmediateOperand
if isinstance(operand, RegisterOperand) and 'r' not in allowed:
raise OperandMismatchError(None, allowed, operand)
if isinstance(operand, ImmediateOperand) and 'i' not in allowed:
raise OperandMismatchError(None, allowed, operand)
@staticmethod
[docs] def emit_instruction(ctx, desc, operands):
D = ctx.DEBUG
binst = desc.encoding()
D('emit_instruction: desc=%s, encoding=%s', desc.__class__.__name__, desc.encoding.__name__)
binst.opcode = desc.opcode
D('emit_instruction: desc.operands=%s, operands=%s', desc.operands, operands)
if isinstance(desc.operands, string_types):
desc._expand_operands()
for index, allowed_types, operand in zip(range(0, len(desc.operands)), desc.operands, operands):
D('emit_instruction: check operand: allowed=%s, operand=%s', allowed_types, operand)
Descriptor._match_operand_type(allowed_types, operand)
desc.assemble_operands(ctx, binst, operands)
return binst
[docs]class Descriptor_R(Descriptor):
operands = 'r'
encoding = EncodingR
@staticmethod
[docs] def assemble_operands(ctx, inst, operands):
ctx.encode(inst, 'reg1', 5, operands[0].operand)
@staticmethod
[docs] def disassemble_operands(logger, inst):
return [REGISTER_NAMES[inst.reg1]]
[docs]class Descriptor_RI(Descriptor):
operands = 'ri'
encoding = EncodingI
@staticmethod
[docs] def assemble_operands(ctx, inst, operands):
from ..asm.ast import RegisterOperand, ReferenceOperand
op = operands[0]
if isinstance(op, RegisterOperand):
ctx.encode(inst, 'reg', 5, op.operand)
else:
ctx.encode(inst, 'immediate_flag', 1, 1)
if isinstance(op, ReferenceOperand):
inst.refers_to = op
else:
ctx.encode(inst, 'immediate', 20, op.operand)
@staticmethod
[docs] def disassemble_operands(logger, inst):
if inst.immediate_flag == 0:
return [REGISTER_NAMES[inst.reg]]
return [str(inst.refers_to) if hasattr(inst, 'refers_to') and inst.refers_to is not None else UINT32_FMT(inst.immediate)]
[docs]class Descriptor_R_I(Descriptor):
operands = 'r,i'
encoding = EncodingI
@staticmethod
[docs] def assemble_operands(ctx, inst, operands):
from ..asm.ast import ReferenceOperand
ctx.encode(inst, 'reg', 5, operands[0].operand)
ctx.encode(inst, 'immediate_flag', 1, 1)
op = operands[1]
if isinstance(op, ReferenceOperand):
inst.refers_to = op
else:
ctx.encode(inst, 'immediate', 20, op.operand)
@staticmethod
[docs] def disassemble_operands(logger, inst):
return [REGISTER_NAMES[inst.reg], str(inst.refers_to) if hasattr(inst, 'refers_to') and inst.refers_to is not None else UINT20_FMT(inst.immediate)]
[docs]class Descriptor_R_RI(Descriptor):
operands = 'r,ri'
encoding = EncodingR
@staticmethod
[docs] def assemble_operands(ctx, inst, operands):
from ..asm.ast import RegisterOperand, ReferenceOperand
ctx.encode(inst, 'reg1', 5, operands[0].operand)
op = operands[1]
if isinstance(op, RegisterOperand):
ctx.encode(inst, 'reg2', 5, op.operand)
else:
ctx.encode(inst, 'immediate_flag', 1, 1)
if isinstance(op, ReferenceOperand):
inst.refers_to = op
else:
ctx.encode(inst, 'immediate', 15, op.operand)
@staticmethod
[docs] def disassemble_operands(logger, inst):
if inst.immediate_flag == 0:
return [REGISTER_NAMES[inst.reg1], REGISTER_NAMES[inst.reg2]]
return [REGISTER_NAMES[inst.reg1], str(inst.refers_to) if hasattr(inst, 'refers_to') and inst.refers_to is not None else UINT16_FMT(inst.immediate)]
[docs]class Descriptor_R_R(Descriptor):
operands = 'r,r'
encoding = EncodingR
@staticmethod
[docs] def assemble_operands(ctx, inst, operands):
ctx.encode(inst, 'reg1', 5, operands[0].operand)
ctx.encode(inst, 'reg2', 5, operands[1].operand)
@staticmethod
[docs] def disassemble_operands(logger, inst):
return [REGISTER_NAMES[inst.reg1], REGISTER_NAMES[inst.reg2]]
@add_metaclass(InstructionSetMetaclass)
[docs]class InstructionSet(object):
instruction_set_id = None
opcodes = None
@classmethod
[docs] def init(cls):
if hasattr(cls, 'opcode_desc_map'):
return
cls.opcode_desc_map = {}
cls.opcode_encoding_map = {}
for desc in cls.instructions:
cls.opcode_desc_map[desc.opcode] = desc
cls.opcode_encoding_map[desc.opcode] = desc.encoding
@classmethod
[docs] def disassemble_instruction(cls, logger, inst):
logger.debug('%s.disassemble_instruction: inst=%s (%s)', cls.__name__, inst, inst.__class__.__name__)
if isinstance(inst, ctypes.LittleEndianStructure):
inst, desc = inst, cls.opcode_desc_map[inst.opcode]
else:
inst, desc, _ = EncodingContext(logger).decode(cls, inst)
mnemonic = desc.disassemble_mnemonic(inst)
operands = desc.disassemble_operands(logger, inst)
return (mnemonic + ' ' + ', '.join(operands)) if operands else mnemonic
#
# Main instruction set
#
[docs]def RI_VAL(core, inst, reg, sign_extend = True):
if inst.immediate_flag == 1:
if sign_extend is True:
return inst.sign_extend_immediate(core.LOGGER, inst)
return inst.immediate % 4294967296
return core.registers[getattr(inst, reg)]
[docs]def RI_ADDR(core, inst, reg):
core.DEBUG('RI_ADDR: inst=%s, reg=%s', inst, reg)
base = core.registers[reg]
offset = inst.sign_extend_immediate(core.LOGGER, inst) if inst.immediate_flag == 1 else 0
return (base + offset) % 4294967296
[docs]def JUMP(core, inst, reg):
core.DEBUG('JUMP: inst=%s', inst)
core.DEBUG(' IP=%s', UINT32_FMT(core.registers[Registers.IP]))
if inst.immediate_flag == 0:
reg = getattr(inst, reg)
core.DEBUG(' register=%d, value=%s', reg, UINT32_FMT(core.registers[reg]))
core.registers[Registers.IP] = core.registers[reg]
else:
v = inst.sign_extend_immediate(core.LOGGER, inst)
nip = (core.registers[Registers.IP] + (v << 2)) % 4294967296
core.DEBUG(' offset=%s, aligned=%s, ip=%s, new=%s', UINT32_FMT(v), UINT32_FMT(v << 2), UINT32_FMT(core.registers[Registers.IP]), UINT32_FMT(nip))
core.registers[Registers.IP] = nip
core.DEBUG('JUMP: new ip=%s', UINT32_FMT(core.registers[Registers.IP]))
[docs]def update_arith_flags(core, reg):
"""
Set relevant arithmetic flags according to content of registers. Flags are set to zero at the beginning,
then content of each register is examined, and ``S`` and ``Z`` flags are set.
``E`` flag is not touched, ``O`` flag is set to zero.
:param u32_t reg: register
"""
core.arith_zero = False
core.arith_overflow = False
core.arith_sign = False
if reg == 0:
core.arith_zero = True
if reg & 0x80000000 != 0:
core.arith_sign = True
[docs]class DuckyOpcodes(enum.IntEnum):
NOP = 0
# Memory load/store
LW = 1
LS = 2
LB = 3
STW = 4
STS = 5
STB = 6
CAS = 7
LA = 8
LI = 9
LIU = 10
MOV = 11
SWP = 12
INT = 13
RETINT = 14
CALL = 15
RET = 16
CLI = 17
STI = 18
RST = 19
HLT = 20
IDLE = 21
LPM = 22
IPI = 23
PUSH = 24
POP = 25
INC = 26
DEC = 27
ADD = 28
SUB = 29
MUL = 30
DIV = 31
UDIV = 32
MOD = 33
AND = 34
OR = 35
XOR = 36
NOT = 37
SHL = 38
SHR = 39
SHRS = 40
# Branch instructions
J = 46
# Condition instructions
CMP = 47
CMPU = 48
SET = 49
BRANCH = 50
SELECT = 51
# Control instructions
CTR = 60
CTW = 61
FPTC = 62
SIS = 63
[docs]class NOP(Descriptor):
mnemonic = 'nop'
opcode = DuckyOpcodes.NOP
encoding = EncodingI
@staticmethod
[docs] def execute(core, inst):
pass
#
# Interrupts
#
[docs]class INT(Descriptor_RI):
mnemonic = 'int'
opcode = DuckyOpcodes.INT
@staticmethod
[docs] def execute(core, inst):
core._enter_exception(RI_VAL(core, inst, 'reg'))
[docs]class IPI(Descriptor_R_RI):
mnemonic = 'ipi'
opcode = DuckyOpcodes.IPI
@staticmethod
[docs] def execute(core, inst):
core.check_protected_ins()
cpuid = core.registers[inst.reg1]
cpuid, coreid = cpuid >> 16, cpuid & 0xFFFF
core.cpu.machine.cpus[cpuid].cores[coreid].irq(RI_VAL(core, inst, 'reg2'))
[docs]class RETINT(Descriptor):
mnemonic = 'retint'
opcode = DuckyOpcodes.RETINT
encoding = EncodingI
@staticmethod
[docs] def execute(core, inst):
core.check_protected_ins()
core.pop_frame()
core._exit_exception()
@staticmethod
[docs] def jit(core, inst):
exit_exception = core._exit_exception
err = PrivilegedInstructionError(core = core)
def __jit_retint():
if core.privileged is False:
raise err
exit_exception()
return __jit_retint
#
# Jumps
#
[docs]class _JUMP(Descriptor):
operands = 'ri'
encoding = EncodingI
relative_address = True
inst_aligned = True
@staticmethod
[docs] def assemble_operands(ctx, inst, operands):
from ..asm.ast import RegisterOperand, ReferenceOperand
op = operands[0]
if isinstance(op, RegisterOperand):
ctx.encode(inst, 'reg', 5, op.operand)
else:
ctx.encode(inst, 'immediate_flag', 1, 1)
if isinstance(op, ReferenceOperand):
inst.refers_to = op
else:
ctx.encode(inst, 'immediate', 20, op.operand >> 2)
@staticmethod
[docs] def disassemble_operands(logger, inst):
if inst.immediate_flag == 0:
return [REGISTER_NAMES[inst.reg]]
return [str(inst.refers_to) if hasattr(inst, 'refers_to') and inst.refers_to is not None else UINT32_FMT(inst.immediate << 2)]
[docs]class CALL(_JUMP):
mnemonic = 'call'
opcode = DuckyOpcodes.CALL
@staticmethod
[docs] def execute(core, inst):
frame = core.create_frame()
JUMP(core, inst, 'reg')
frame.IP = core.registers[Registers.IP]
core.frames.append(frame)
@staticmethod
[docs] def jit(core, inst):
regset = core.registers
push = core._raw_push
ip = Registers.IP.value
fp = Registers.FP.value
sp = Registers.SP.value
if inst.immediate_flag == 0:
reg = inst.reg
def __jit_call():
push(regset[ip])
push(regset[fp])
regset[fp] = regset[sp]
regset[ip] = regset[reg]
return __jit_call
else:
i = inst.sign_extend_immediate(core.LOGGER, inst) << 2
def __jit_call():
push(regset[ip])
push(regset[fp])
regset[fp] = regset[sp]
regset[ip] = (regset[ip] + i) % 4294967296
return __jit_call
[docs]class J(_JUMP):
mnemonic = 'j'
opcode = DuckyOpcodes.J
@staticmethod
[docs] def execute(core, inst):
JUMP(core, inst, 'reg')
@staticmethod
[docs] def jit(core, inst):
regset = core.registers
ip = Registers.IP.value
if inst.immediate_flag == 0:
reg = inst.reg
def __jit_j():
regset[ip] = regset[reg]
return __jit_j
else:
i = inst.sign_extend_immediate(core.LOGGER, inst) << 2
def __jit_j():
regset[ip] = (regset[ip] + i) % 4294967296
return __jit_j
[docs]class RET(Descriptor):
mnemonic = 'ret'
opcode = DuckyOpcodes.RET
encoding = EncodingI
@staticmethod
[docs] def execute(core, inst):
core.pop_frame()
core.destroy_frame()
@staticmethod
[docs] def jit(core, inst):
regset = core.registers
pop = core._raw_pop
fp = Registers.FP.value
ip = Registers.IP.value
def __jit_ret():
regset[fp] = pop()
regset[ip] = pop()
return __jit_ret
#
# CPU
#
[docs]class LPM(Descriptor):
mnemonic = 'lpm'
opcode = DuckyOpcodes.LPM
encoding = EncodingI
@staticmethod
[docs] def execute(core, inst):
core.check_protected_ins()
core.privileged = False
[docs]class CLI(Descriptor):
mnemonic = 'cli'
opcode = DuckyOpcodes.CLI
encoding = EncodingI
@staticmethod
[docs] def execute(core, inst):
core.check_protected_ins()
core.hwint_allowed = False
@staticmethod
[docs] def jit(core, inst):
err = PrivilegedInstructionError(core = core)
def __jit_cli():
if core.privileged is False:
raise err
core.hwint_allowed = False
return __jit_cli
[docs]class STI(Descriptor):
mnemonic = 'sti'
opcode = DuckyOpcodes.STI
encoding = EncodingI
@staticmethod
[docs] def execute(core, inst):
core.check_protected_ins()
core.hwint_allowed = True
@staticmethod
[docs] def jit(core, inst):
err = PrivilegedInstructionError(core = core)
def __jit_sti():
if core.privileged is False:
raise err
core.hwint_allowed = True
return __jit_sti
[docs]class HLT(Descriptor_RI):
mnemonic = 'hlt'
opcode = DuckyOpcodes.HLT
@staticmethod
[docs] def execute(core, inst):
core.check_protected_ins()
core.exit_code = RI_VAL(core, inst, 'reg')
core.halt()
[docs]class RST(Descriptor):
mnemonic = 'rst'
opcode = DuckyOpcodes.RST
encoding = EncodingI
@staticmethod
[docs] def execute(core, inst):
core.check_protected_ins()
core.reset()
[docs]class IDLE(Descriptor):
mnemonic = 'idle'
opcode = DuckyOpcodes.IDLE
encoding = EncodingI
@staticmethod
[docs] def execute(core, inst):
core.change_runnable_state(idle = True)
[docs]class SIS(Descriptor_RI):
mnemonic = 'sis'
opcode = DuckyOpcodes.SIS
@staticmethod
[docs] def execute(core, inst):
core.instruction_set = get_instruction_set(RI_VAL(core, inst, 'reg'))
@staticmethod
[docs] def jit(core, inst):
if inst.immediate_flag == 0:
regset = core.registers
reg = inst.reg
def __jit_sis():
core.instruction_set = INSTRUCTION_SETS[regset[reg]]
return __jit_sis
else:
i = inst.sign_extend_immediate(core.LOGGER, inst)
def __jit_sis():
core.instruction_set = INSTRUCTION_SETS[i]
return __jit_sis
#
# Stack
#
[docs]class PUSH(Descriptor_RI):
mnemonic = 'push'
opcode = DuckyOpcodes.PUSH
@staticmethod
[docs] def execute(core, inst):
core._raw_push(RI_VAL(core, inst, 'reg'))
@staticmethod
[docs] def jit(core, inst):
push = core._raw_push
regset = core.registers
if inst.immediate_flag == 0:
reg = inst.reg
def __jit_push():
push(regset[reg])
return __jit_push
else:
i = inst.sign_extend_immediate(core.LOGGER, inst)
def __jit_push():
push(i)
return __jit_push
[docs]class POP(Descriptor_R):
mnemonic = 'pop'
opcode = DuckyOpcodes.POP
@staticmethod
[docs] def execute(core, inst):
core.pop(inst.reg1)
update_arith_flags(core, core.registers[inst.reg1])
@staticmethod
[docs] def jit(core, inst):
pop = core._raw_pop
regset = core.registers
reg = inst.reg1
def __jit_pop():
regset[reg] = v = pop()
core.arith_zero = v == 0
core.arith_overflow = False
core.arith_sign = (v & 0x80000000) != 0
return __jit_pop
#
# Arithmetic
#
[docs]class INC(Descriptor_R):
mnemonic = 'inc'
opcode = DuckyOpcodes.INC
@staticmethod
[docs] def execute(core, inst):
core.registers[inst.reg1] = (core.registers[inst.reg1] + 1) % 4294967296
update_arith_flags(core, core.registers[inst.reg1])
core.arith_overflow = core.registers[inst.reg1] == 0
@staticmethod
[docs] def jit(core, inst):
regset = core.registers
reg = inst.reg1
def __jit_inc():
old, new = regset[reg], (regset[reg] + 1) % 4294967296
regset[reg] = new
if old == 0:
core.arith_zero = core.arith_overflow = core.arith_sign = False
elif old == 0xFFFFFFFF:
core.arith_zero = core.arith_overflow = True
core.arith_sign = False
else:
core.arith_zero = False
core.arith_overflow = False
core.arith_sign = (new & 0x80000000) != 0
return __jit_inc
[docs]class DEC(Descriptor_R):
mnemonic = 'dec'
opcode = DuckyOpcodes.DEC
@staticmethod
[docs] def execute(core, inst):
core.registers[inst.reg1] = (core.registers[inst.reg1] - 1) % 4294967296
update_arith_flags(core, core.registers[inst.reg1])
@staticmethod
[docs] def jit(core, inst):
regset = core.registers
reg = inst.reg1
def __jit_dec():
old, new = regset[reg], (regset[reg] - 1) % 4294967296
regset[reg] = new
if old == 0:
core.arith_zero = core.arith_overflow = False
core.arith_sign = True
elif old == 1:
core.arith_zero = True
core.arith_overflow = core.arith_sign = False
else:
core.arith_zero = core.arith_overflow = False
core.arith_sign = (new & 0x80000000) != 0
return __jit_dec
[docs]class _BINOP(Descriptor_R_RI):
encoding = EncodingR
@staticmethod
[docs] def execute(core, inst):
regset = core.registers
r = regset[inst.reg1]
v = RI_VAL(core, inst, 'reg2')
if inst.opcode == DuckyOpcodes.ADD:
v = (r + v)
elif inst.opcode == DuckyOpcodes.SUB:
v = (r - v)
elif inst.opcode == DuckyOpcodes.MUL:
x = i32_t(r).value
y = i32_t(v).value
v = x * y
elif inst.opcode == DuckyOpcodes.DIV:
y = i32_t(v).value
if y == 0:
raise DivideByZeroError(core = core)
x = i32_t(r).value
if abs(y) > abs(x):
v = 0
else:
v = x // y
elif inst.opcode == DuckyOpcodes.UDIV:
y = u32_t(v).value
if y == 0:
raise DivideByZeroError(core = core)
x = u32_t(r).value
v = x // y
elif inst.opcode == DuckyOpcodes.MOD:
y = i32_t(v).value
if y == 0:
raise DivideByZeroError(core = core)
x = i32_t(r).value
v = x % y
regset[inst.reg1] = v % 4294967296
update_arith_flags(core, regset[inst.reg1])
if v > 0xFFFFFFFF:
core.arith_overflow = True
[docs]class ADD(_BINOP):
mnemonic = 'add'
opcode = DuckyOpcodes.ADD
@staticmethod
[docs] def jit(core, inst):
regset = core.registers
if inst.immediate_flag == 1:
reg = inst.reg1
i = inst.sign_extend_immediate(core.LOGGER, inst)
def __jit_add():
v = regset[reg] + i
regset[reg] = r = v % 4294967296
core.arith_zero = r == 0
core.arith_overflow = v > 0xFFFFFFFF
core.arith_sign = (v & 0x80000000) != 0
return __jit_add
else:
reg1, reg2 = inst.reg1, inst.reg2
def __jit_add():
v = regset[reg1] + regset[reg2]
regset[reg1] = r = v % 4294967296
core.arith_zero = r == 0
core.arith_overflow = v > 0xFFFFFFFF
core.arith_sign = (v & 0x80000000) != 0
return __jit_add
[docs]class SUB(_BINOP):
mnemonic = 'sub'
opcode = DuckyOpcodes.SUB
@staticmethod
[docs] def jit(core, inst):
regset = core.registers
if inst.immediate_flag == 1:
reg = inst.reg1
i = inst.sign_extend_immediate(core.LOGGER, inst)
def __jit_sub():
v = regset[reg] - i
regset[reg] = r = v % 4294967296
core.arith_zero = r == 0
core.arith_overflow = v > 0xFFFFFFFF
core.arith_sign = (v & 0x80000000) != 0
return __jit_sub
else:
reg1, reg2 = inst.reg1, inst.reg2
def __jit_sub():
v = regset[reg1] - regset[reg2]
regset[reg1] = r = v % 4294967296
core.arith_zero = r == 0
core.arith_overflow = v > 0xFFFFFFFF
core.arith_sign = (v & 0x80000000) != 0
return __jit_sub
[docs]class MUL(_BINOP):
mnemonic = 'mul'
opcode = DuckyOpcodes.MUL
@staticmethod
[docs] def jit(core, inst):
regset = core.registers
if inst.immediate_flag == 1:
reg = inst.reg1
i = i32_t(inst.sign_extend_immediate(core.LOGGER, inst)).value
def __jit_mul():
v = i32_t(regset[reg]).value * i
regset[reg] = r = v % 4294967296
core.arith_zero = r == 0
core.arith_overflow = v > 0xFFFFFFFF
core.arith_sign = (v & 0x80000000) != 0
return __jit_mul
else:
reg1, reg2 = inst.reg1, inst.reg2
def __jit_mul():
v = i32_t(regset[reg1]).value * i32_t(regset[reg2]).value
regset[reg1] = r = v % 4294967296
core.arith_zero = r == 0
core.arith_overflow = v > 0xFFFFFFFF
core.arith_sign = (v & 0x80000000) != 0
return __jit_mul
[docs]class DIV(_BINOP):
mnemonic = 'div'
opcode = DuckyOpcodes.DIV
@staticmethod
[docs] def jit(core, inst):
regset = core.registers
err = DivideByZeroError(core = core)
if inst.immediate_flag == 1:
y = inst.sign_extend_immediate(core.LOGGER, inst)
if y == 0:
def __jit_div():
raise err
return __jit_div
else:
reg = inst.reg1
y_i = i32_t(y).value
y_a = abs(y_i)
def __jit_div():
x = regset[reg]
x_i = i32_t(x).value
if y_a > abs(x_i):
r = 0
core.arith_zero = True
else:
r = x_i // y_i
core.arith_zero = False
regset[reg] = r % 4294967296
core.arith_overflow = False
core.arith_sign = (r & 0x80000000) != 0
return __jit_div
else:
reg1 = inst.reg1
reg2 = inst.reg2
def __jit_div():
y = regset[reg2]
if y == 0:
raise err
y_i = i32_t(y).value
y_a = abs(y_i)
x = regset[reg1]
x_i = i32_t(x).value
x_a = abs(x_i)
if y_a > x_a:
r = 0
core.arith_zero = True
else:
r = x_i // y_i
core.arith_zero = False
regset[reg1] = r % 4294967296
core.arith_overflow = False
core.arith_sign = (r & 0x80000000) != 0
return __jit_div
[docs]class UDIV(_BINOP):
mnemonic = 'udiv'
opcode = DuckyOpcodes.UDIV
@staticmethod
[docs] def jit(core, inst):
regset = core.registers
err = DivideByZeroError(core = core)
if inst.immediate_flag == 1:
y = inst.sign_extend_immediate(core.LOGGER, inst)
if y == 0:
def __jit_udiv():
raise err
return __jit_udiv
else:
reg = inst.reg1
def __jit_udiv():
x = regset[reg]
r = x // y
regset[reg] = r % 4294967296
core.arith_zero = r == 0
core.arith_overflow = False
core.arith_sign = (r & 0x80000000) != 0
return __jit_udiv
else:
reg1 = inst.reg1
reg2 = inst.reg2
def __jit_udiv():
y = regset[reg2]
if y == 0:
raise err
x = regset[reg1]
r = x // y
regset[reg1] = r % 4294967296
core.arith_zero = r == 0
core.arith_overflow = False
core.arith_sign = (r & 0x80000000) != 0
return __jit_udiv
[docs]class MOD(_BINOP):
mnemonic = 'mod'
opcode = DuckyOpcodes.MOD
@staticmethod
[docs] def jit(core, inst):
regset = core.registers
err = DivideByZeroError(core = core)
if inst.immediate_flag == 1:
y = inst.sign_extend_immediate(core.LOGGER, inst)
if y == 0:
def __jit_mod():
raise err
return __jit_mod
else:
reg = inst.reg1
y_i = i32_t(y).value
def __jit_mod():
x_i = i32_t(regset[reg]).value
r = x_i % y_i
regset[reg] = r % 4294967296
core.arith_zero = r == 0
core.arith_overflow = False
core.arith_sign = (r & 0x80000000) != 0
return __jit_mod
else:
reg1 = inst.reg1
reg2 = inst.reg2
def __jit_mod():
y = regset[reg2]
if y == 0:
raise err
y_i = i32_t(y).value
x_i = i32_t(regset[reg1]).value
r = x_i % y_i
regset[reg1] = r % 4294967296
core.arith_zero = r == 0
core.arith_overflow = False
core.arith_sign = (r & 0x80000000) != 0
return __jit_mod
#
# Conditional and unconditional jumps
#
[docs]class _COND(Descriptor):
FLAGS = ['arith_equal', 'arith_zero', 'arith_overflow', 'arith_sign', 'l', 'g']
GFLAGS = [0, 1, 2, 3]
MNEMONICS = ['e', 'z', 'o', 's', 'g', 'l']
@staticmethod
[docs] def set_condition(ctx, inst, flag, value):
ctx.DEBUG('set_condition: flag=%s, value=%s', flag, value)
ctx.encode(inst, 'flag', 3, _COND.FLAGS.index(flag))
ctx.encode(inst, 'value', 1, 1 if value is True else 0)
@staticmethod
[docs] def evaluate(core, inst):
# genuine flags
if inst.flag in _COND.GFLAGS and inst.value == getattr(core, _COND.FLAGS[inst.flag]):
return True
# "less than" flag
if inst.flag == 4:
if inst.value == 1 and core.arith_sign is True and core.arith_equal is not True:
return True
if inst.value == 0 and (core.arith_sign is not True or core.arith_equal is True):
return True
# "greater than" flag
if inst.flag == 5:
if inst.value == 1 and core.arith_sign is not True and core.arith_equal is not True:
return True
if inst.value == 0 and (core.arith_sign is True or core.arith_equal is True):
return True
return False
[docs]class _BRANCH(_COND):
encoding = EncodingC
operands = 'ri'
opcode = DuckyOpcodes.BRANCH
relative_address = True
inst_aligned = True
@classmethod
[docs] def assemble_operands(cls, ctx, inst, operands):
from ..asm.ast import RegisterOperand, ReferenceOperand
op = operands[0]
if isinstance(op, RegisterOperand):
ctx.encode(inst, 'reg', 5, op.operand)
else:
ctx.encode(inst, 'immediate_flag', 1, 1)
if isinstance(op, ReferenceOperand):
inst.refers_to = op
else:
v = op.operand
if v & 0x3 != 0:
raise buffer.get_error(UnalignedJumpTargetError, 'address=%s' % UINT32_FMT(v))
ctx.encode(inst, 'immediate', 16, v >> 2)
set_condition = partial(_COND.set_condition, ctx, inst)
if cls is BE:
set_condition('arith_equal', True)
elif cls is BNE:
set_condition('arith_equal', False)
elif cls is BZ:
set_condition('arith_zero', True)
elif cls is BNZ:
set_condition('arith_zero', False)
elif cls is BO:
set_condition('arith_overflow', True)
elif cls is BNO:
set_condition('arith_overflow', False)
elif cls is BS:
set_condition('arith_sign', True)
elif cls is BNS:
set_condition('arith_sign', False)
elif cls is BL:
set_condition('l', True)
elif cls is BLE:
set_condition('g', False)
elif cls is BG:
set_condition('g', True)
elif cls is BGE:
set_condition('l', False)
@staticmethod
[docs] def fill_reloc_slot(inst, slot):
inst.fill_reloc_slot(inst, slot)
slot.flags.inst_aligned = True
@staticmethod
[docs] def disassemble_operands(logger, inst):
if inst.immediate_flag == 0:
return [REGISTER_NAMES[inst.reg]]
return [str(inst.refers_to) if hasattr(inst, 'refers_to') and inst.refers_to is not None else UINT32_FMT(inst.immediate << 2)]
@staticmethod
[docs] def disassemble_mnemonic(inst):
if inst.flag in _COND.GFLAGS:
return 'b%s%s' % ('n' if inst.value == 0 else '', _COND.MNEMONICS[inst.flag])
else:
if inst.flag == _COND.FLAGS.index('l'):
return 'bl' if inst.value == 1 else 'bge'
elif inst.flag == _COND.FLAGS.index('g'):
return 'bg' if inst.value == 1 else 'ble'
@staticmethod
[docs] def execute(core, inst):
if _COND.evaluate(core, inst):
JUMP(core, inst, 'reg')
@staticmethod
[docs] def jit(core, inst):
core.DEBUG('JIT: %s', inst)
regset = core.registers
ip = Registers.IP.value
if inst.immediate_flag == 1:
i = inst.sign_extend_immediate(core.LOGGER, inst) << 2
else:
reg = inst.reg
if inst.flag == 0:
if inst.value == 0:
if inst.immediate_flag == 0:
def __branch_ne():
if core.arith_equal is False:
regset[ip] = regset[reg]
return __branch_ne
else:
def __branch_ne():
if core.arith_equal is False:
regset[ip] = (regset[ip] + i) % 4294967296
return __branch_ne
else:
if inst.immediate_flag == 0:
def __branch_e():
if core.arith_equal is True:
regset[ip] = regset[reg]
return __branch_e
else:
def __branch_e():
if core.arith_equal is True:
regset[ip] = (regset[ip] + i) % 4294967296
return __branch_e
elif inst.flag == 1:
if inst.value == 0:
if inst.immediate_flag == 0:
def __branch_nz():
if core.arith_zero is False:
regset[ip] = regset[reg]
return __branch_nz
else:
def __branch_nz():
if core.arith_zero is False:
regset[ip] = (regset[ip] + i) % 4294967296
return __branch_nz
else:
if inst.immediate_flag == 0:
def __branch_z():
if core.arith_zero is True:
regset[ip] = regset[reg]
return __branch_z
else:
def __branch_z():
if core.arith_zero is True:
regset[ip] = (regset[ip] + i) % 4294967296
return __branch_z
elif inst.flag == 2:
if inst.value == 0:
if inst.immediate_flag == 0:
def __branch_no():
if core.arith_overflow is False:
regset[ip] = regset[reg]
return __branch_no
else:
def __branch_no():
if core.arith_overflow is False:
regset[ip] = (regset[ip] + i) % 4294967296
return __branch_no
else:
if inst.immediate_flag == 0:
def __branch_o():
if core.arith_overflow is True:
regset[ip] = regset[reg]
return __branch_o
else:
def __branch_o():
if core.arith_overflow is True:
regset[ip] = (regset[ip] + i) % 4294967296
return __branch_o
elif inst.flag == 3:
if inst.value == 0:
if inst.immediate_flag == 0:
def __branch_ns():
if core.arith_sign is False:
regset[ip] = regset[reg]
return __branch_ns
else:
def __branch_ns():
if core.arith_sign is False:
regset[ip] = (regset[ip] + i) % 4294967296
return __branch_ns
else:
if inst.immediate_flag == 0:
def __branch_s():
if core.arith_sign is True:
regset[ip] = regset[reg]
return __branch_s
else:
def __branch_s():
if core.arith_sign is True:
regset[ip] = (regset[ip] + i) % 4294967296
return __branch_s
elif inst.flag == 4:
if inst.value == 0:
if inst.immediate_flag == 0:
def __branch_ge():
if core.arith_sign is False or core.arith_equal is True:
regset[ip] = regset[reg]
return __branch_ge
else:
def __branch_ge():
if core.arith_sign is False or core.arith_equal is True:
regset[ip] = (regset[ip] + i) % 4294967296
return __branch_ge
else:
if inst.immediate_flag == 0:
def __branch_l():
if core.arith_sign is True and core.arith_equal is False:
regset[ip] = regset[reg]
return __branch_l
else:
def __branch_l():
if core.arith_sign is True and core.arith_equal is False:
regset[ip] = (regset[ip] + i) % 4294967296
return __branch_l
elif inst.flag == 5:
if inst.value == 0:
if inst.immediate_flag == 0:
def __branch_le():
if core.arith_sign is True or core.arith_equal is True:
regset[ip] = regset[reg]
return __branch_le
else:
def __branch_le():
if core.arith_sign is True or core.arith_equal is True:
regset[ip] = (regset[ip] + i) % 4294967296
return __branch_le
else:
if inst.immediate_flag == 0:
def __branch_g():
if core.arith_sign is False and core.arith_equal is False:
regset[ip] = regset[reg]
return __branch_g
else:
def __branch_g():
if core.arith_sign is False and core.arith_equal is False:
regset[ip] = (regset[ip] + i) % 4294967296
return __branch_g
return None
[docs]class _SET(_COND):
encoding = EncodingS
operands = 'r'
opcode = DuckyOpcodes.SET
@classmethod
[docs] def assemble_operands(cls, ctx, inst, operands):
ctx.encode(inst, 'reg1', 5, operands[0].operand)
set_condition = partial(_COND.set_condition, ctx, inst)
if cls is SETE:
set_condition('arith_equal', True)
elif cls is SETNE:
set_condition('arith_equal', False)
elif cls is SETZ:
set_condition('arith_zero', True)
elif cls is SETNZ:
set_condition('arith_zero', False)
elif cls is SETO:
set_condition('arith_overflow', True)
elif cls is SETNO:
set_condition('arith_overflow', False)
elif cls is SETS:
set_condition('arith_sign', True)
elif cls is SETNS:
set_condition('arith_sign', False)
elif cls is SETL:
set_condition('l', True)
elif cls is SETLE:
set_condition('g', False)
elif cls is SETG:
set_condition('g', True)
elif cls is SETGE:
set_condition('l', False)
@staticmethod
[docs] def disassemble_operands(logger, inst):
return [REGISTER_NAMES[inst.reg1]]
@staticmethod
[docs] def disassemble_mnemonic(inst):
if inst.flag in _COND.GFLAGS:
return 'set%s%s' % ('n' if inst.value == 0 else '', _COND.MNEMONICS[inst.flag])
else:
return 'set%s%s' % (_COND.MNEMONICS[inst.flag], 'e' if inst.value == 1 else '')
@staticmethod
[docs] def execute(core, inst):
core.registers[inst.reg1] = 1 if _COND.evaluate(core, inst) is True else 0
update_arith_flags(core, core.registers[inst.reg1])
[docs]class _SELECT(Descriptor):
encoding = EncodingS
operands = 'r,ri'
opcode = DuckyOpcodes.SELECT
@classmethod
[docs] def assemble_operands(cls, ctx, inst, operands):
from ..asm.ast import RegisterOperand, ReferenceOperand
ctx.encode(inst, 'reg1', 5, operands[0].operand)
op = operands[1]
if isinstance(op, RegisterOperand):
ctx.encode(inst, 'reg2', 5, op.operand)
else:
ctx.encode(inst, 'immediate_flag', 1, 1)
if isinstance(op, ReferenceOperand):
inst.refers_to = op
else:
ctx.encode(inst, 'immediate', 11, op.operand)
set_condition = partial(_COND.set_condition, ctx, inst)
if cls is SELE:
set_condition('arith_equal', True)
elif cls is SELNE:
set_condition('arith_equal', False)
elif cls is SELZ:
set_condition('arith_zero', True)
elif cls is SELNZ:
set_condition('arith_zero', False)
elif cls is SELO:
set_condition('arith_overflow', True)
elif cls is SELNO:
set_condition('arith_overflow', False)
elif cls is SELS:
set_condition('arith_sign', True)
elif cls is SELNS:
set_condition('arith_sign', False)
elif cls is SELL:
set_condition('l', True)
elif cls is SELLE:
set_condition('g', False)
elif cls is SELG:
set_condition('g', True)
elif cls is SELGE:
set_condition('l', False)
@staticmethod
[docs] def disassemble_operands(logger, inst):
if inst.immediate_flag == 0:
return [REGISTER_NAMES[inst.reg1], REGISTER_NAMES[inst.reg2]]
return [REGISTER_NAMES[inst.reg1], str(inst.refers_to) if hasattr(inst, 'refers_to') and inst.refers_to is not None else UINT32_FMT(inst.immediate)]
@staticmethod
[docs] def disassemble_mnemonic(inst):
if inst.flag in _COND.GFLAGS:
return 'sel%s%s' % ('n' if inst.value == 0 else '', _COND.MNEMONICS[inst.flag])
else:
return 'sel%s%s' % (_COND.MNEMONICS[inst.flag], '' if inst.value == 1 else 'e')
@staticmethod
[docs] def execute(core, inst):
if _COND.evaluate(core, inst) is False:
core.registers[inst.reg1] = RI_VAL(core, inst, 'reg2')
update_arith_flags(core, core.registers[inst.reg1])
@staticmethod
[docs] def jit(core, inst):
regset = core.registers
reg1 = inst.reg1
if inst.immediate_flag == 1:
i = inst.sign_extend_immediate(core.LOGGER, inst)
zero = i == 0
sign = (i & 0x80000000) != 0
else:
reg2 = inst.reg2
if inst.flag == 0:
if inst.value == 0:
if inst.immediate_flag == 0:
def __jit_selne():
if core.arith_equal is True:
regset[reg1] = v = regset[reg2]
else:
v = regset[reg1]
core.arith_zero = v == 0
core.arith_overflow = False
core.arith_sign = (v & 0x80000000) != 0
return __jit_selne
else:
def __jit_selne():
if core.arith_equal is True:
regset[reg1] = i
core.arith_zero = zero
core.arith_sign = sign
else:
v = regset[reg1]
core.arith_zero = v == 0
core.arith_sign = (v & 0x80000000) != 0
core.arith_overflow = False
return __jit_selne
else:
if inst.immediate_flag == 0:
def __jit_sele():
if core.arith_equal is False:
regset[reg1] = v = regset[reg2]
else:
v = regset[reg1]
core.arith_zero = v == 0
core.arith_overflow = False
core.arith_sign = (v & 0x80000000) != 0
return __jit_sele
else:
def __jit_sele():
if core.arith_equal is False:
regset[reg1] = i
core.arith_zero = zero
core.arith_sign = sign
else:
v = regset[reg1]
core.arith_zero = v == 0
core.arith_sign = (v & 0x80000000) != 0
core.arith_overflow = False
return __jit_sele
elif inst.flag == 4:
if inst.value == 0:
if inst.immediate_flag == 0:
def __jit_selge():
if core.arith_sign is True and core.arith_equal is False:
regset[reg1] = v = regset[reg2]
else:
v = regset[reg1]
core.arith_zero = v == 0
core.arith_overflow = False
core.arith_sign = (v & 0x80000000) != 0
return __jit_selge
else:
def __jit_selge():
if core.arith_sign is True and core.arith_equal is False:
regset[reg1] = i
core.arith_zero = zero
core.arith_sign = sign
else:
v = regset[reg1]
core.arith_zero = v == 0
core.arith_sign = (v & 0x80000000) != 0
core.arith_overflow = False
return __jit_selge
else:
if inst.immediate_flag == 0:
def __jit_sell():
if core.arith_sign is False or core.arith_equal is True:
regset[reg1] = v = regset[reg2]
else:
v = regset[reg1]
core.arith_zero = v == 0
core.arith_overflow = False
core.arith_sign = (v & 0x80000000) != 0
return __jit_sell
else:
def __jit_sell():
if core.arith_sign is False or core.arith_equal is True:
regset[reg1] = i
core.arith_zero = zero
core.arith_sign = sign
else:
v = regset[reg1]
core.arith_zero = v == 0
core.arith_sign = (v & 0x80000000) != 0
core.arith_overflow = False
return __jit_sell
elif inst.flag == 5:
if inst.value == 0:
if inst.immediate_flag == 0:
def __jit_selle():
if core.arith_sign is False and core.arith_equal is False:
regset[reg1] = v = regset[reg2]
else:
v = regset[reg1]
core.arith_zero = v == 0
core.arith_overflow = False
core.arith_sign = (v & 0x80000000) != 0
return __jit_selle
else:
def __jit_selle():
if core.arith_sign is False and core.arith_equal is False:
regset[reg1] = i
core.arith_zero = zero
core.arith_sign = sign
else:
v = regset[reg1]
core.arith_zero = v == 0
core.arith_sign = (v & 0x80000000) != 0
core.arith_overflow = False
return __jit_selle
else:
if inst.immediate_flag == 0:
def __jit_selg():
if core.arith_sign is True or core.arith_equal is True:
regset[reg1] = v = regset[reg2]
else:
v = regset[reg1]
core.arith_zero = v == 0
core.arith_overflow = False
core.arith_sign = (v & 0x80000000) != 0
return __jit_selg
else:
def __jit_selg():
if core.arith_sign is True or core.arith_equal is True:
regset[reg1] = i
core.arith_zero = zero
core.arith_sign = sign
else:
v = regset[reg1]
core.arith_zero = v == 0
core.arith_sign = (v & 0x80000000) != 0
core.arith_overflow = False
return __jit_selg
[docs]class _CMP(Descriptor_R_RI):
encoding = EncodingR
@staticmethod
[docs] def evaluate(core, x, y, signed = True):
"""
Compare two numbers, and update relevant flags. Signed comparison is used unless ``signed`` is ``False``.
All arithmetic flags are set to zero before the relevant ones are set.
``O`` flag is reset like the others, therefore caller has to take care of it's setting if it's required
to set it.
:param u32 x: left hand number
:param u32 y: right hand number
:param bool signed: use signed, defaults to ``True``
"""
core.arith_equal = False
core.arith_zero = False
core.arith_overflow = False
core.arith_sign = False
if x == y:
core.arith_equal = True
if x == 0:
core.arith_zero = True
return
if signed:
if (x & 0x80000000 != 0):
x = i32_t(x).value
if (y & 0x80000000 != 0):
y = i32_t(y).value
if x < y:
core.arith_sign = True
[docs]class CMP(_CMP):
mnemonic = 'cmp'
opcode = DuckyOpcodes.CMP
@staticmethod
[docs] def execute(core, inst):
_CMP.evaluate(core, core.registers[inst.reg1], RI_VAL(core, inst, 'reg2'))
@staticmethod
[docs] def jit(core, inst):
regset = core.registers
if inst.immediate_flag == 0:
reg1, reg2 = inst.reg1, inst.reg2
def __jit_cmp():
x = regset[reg1]
y = regset[reg2]
core.arith_overflow = False
if x == y:
core.arith_equal = True
core.arith_zero = x == 0
core.arith_sign = False
return
core.arith_equal = False
core.arith_zero = False
xs = (x & 0x80000000) != 0
ys = (y & 0x80000000) != 0
if xs:
if ys:
# x < 0, y < 0
core.arith_sign = abs(x) < abs(y)
else:
# x < 0, y >= =
core.arith_sign = True
else:
if ys:
# x >= 0, y < 0
core.arith_sign = False
else:
# x >= 0, y >= 0
core.arith_sign = x < y
return __jit_cmp
else:
reg = inst.reg1
y = inst.sign_extend_immediate(core.LOGGER, inst)
ys = (y & 0x80000000) != 0
def __jit_cmp():
x = regset[reg]
core.arith_overflow = False
if x == y:
core.arith_equal = True
core.arith_zero = x == 0
core.arith_sign = False
return
core.arith_equal = False
core.arith_zero = False
xs = (x & 0x80000000) != 0
if xs:
if ys:
core.arith_sign = abs(x) < abs(y)
else:
core.arith_sign = True
else:
if ys:
core.arith_sign = False
else:
core.arith_sign = x < y
return __jit_cmp
return None
[docs]class CMPU(_CMP):
mnemonic = 'cmpu'
opcode = DuckyOpcodes.CMPU
@staticmethod
[docs] def execute(core, inst):
_CMP.evaluate(core, core.registers[inst.reg1], RI_VAL(core, inst, 'reg2', sign_extend = False), signed = False)
@staticmethod
[docs] def jit(core, inst):
regset = core.registers
if inst.immediate_flag == 0:
reg1, reg2 = inst.reg1, inst.reg2
def __jit_cmp():
x = regset[reg1]
y = regset[reg2]
core.arith_overflow = False
if x == y:
core.arith_equal = True
core.arith_zero = x == 0
core.arith_sign = False
return
core.arith_equal = False
core.arith_zero = False
core.arith_sign = x < y
return __jit_cmp
else:
reg = inst.reg1
y = inst.immediate
def __jit_cmp():
x = regset[reg]
core.arith_overflow = False
if x == y:
core.arith_equal = True
core.arith_zero = x == 0
core.arith_sign = False
return
core.arith_equal = False
core.arith_zero = False
core.arith_sign = x < y
return __jit_cmp
return None
[docs]class BE(_BRANCH):
mnemonic = 'be'
[docs]class BNE(_BRANCH):
mnemonic = 'bne'
[docs]class BNS(_BRANCH):
mnemonic = 'bns'
[docs]class BNZ(_BRANCH):
mnemonic = 'bnz'
[docs]class BS(_BRANCH):
mnemonic = 'bs'
[docs]class BZ(_BRANCH):
mnemonic = 'bz'
[docs]class BO(_BRANCH):
mnemonic = 'bo'
[docs]class BNO(_BRANCH):
mnemonic = 'bno'
[docs]class BG(_BRANCH):
mnemonic = 'bg'
[docs]class BGE(_BRANCH):
mnemonic = 'bge'
[docs]class BL(_BRANCH):
mnemonic = 'bl'
[docs]class BLE(_BRANCH):
mnemonic = 'ble'
[docs]class SETE(_SET):
mnemonic = 'sete'
[docs]class SETNE(_SET):
mnemonic = 'setne'
[docs]class SETZ(_SET):
mnemonic = 'setz'
[docs]class SETNZ(_SET):
mnemonic = 'setnz'
[docs]class SETO(_SET):
mnemonic = 'seto'
[docs]class SETNO(_SET):
mnemonic = 'setno'
[docs]class SETS(_SET):
mnemonic = 'sets'
[docs]class SETNS(_SET):
mnemonic = 'setns'
[docs]class SETG(_SET):
mnemonic = 'setg'
[docs]class SETGE(_SET):
mnemonic = 'setge'
[docs]class SETL(_SET):
mnemonic = 'setl'
[docs]class SETLE(_SET):
mnemonic = 'setle'
[docs]class SELE(_SELECT):
mnemonic = 'sele'
[docs]class SELNE(_SELECT):
mnemonic = 'selne'
[docs]class SELZ(_SELECT):
mnemonic = 'selz'
[docs]class SELNZ(_SELECT):
mnemonic = 'selnz'
[docs]class SELO(_SELECT):
mnemonic = 'selo'
[docs]class SELNO(_SELECT):
mnemonic = 'selno'
[docs]class SELS(_SELECT):
mnemonic = 'sels'
[docs]class SELNS(_SELECT):
mnemonic = 'selns'
[docs]class SELG(_SELECT):
mnemonic = 'selg'
[docs]class SELGE(_SELECT):
mnemonic = 'selge'
[docs]class SELL(_SELECT):
mnemonic = 'sell'
[docs]class SELLE(_SELECT):
mnemonic = 'selle'
#
# Bit operations
#
[docs]class _BITOP(Descriptor_R_RI):
encoding = EncodingR
@staticmethod
[docs] def execute(core, inst):
r = core.registers[inst.reg1]
v = RI_VAL(core, inst, 'reg2')
if inst.opcode == DuckyOpcodes.AND:
value = r & v
elif inst.opcode == DuckyOpcodes.OR:
value = r | v
elif inst.opcode == DuckyOpcodes.XOR:
value = r ^ v
elif inst.opcode == DuckyOpcodes.SHL:
value = r << min(v, 32)
elif inst.opcode == DuckyOpcodes.SHR:
value = r >> min(v, 32)
elif inst.opcode == DuckyOpcodes.SHRS:
shift = min(v, 32)
if r & 0x80000000 == 0:
value = r >> shift
else:
value = (r >> shift) | (((1 << shift) - 1) << (32 - shift))
core.registers[inst.reg1] = (value % 4294967296)
update_arith_flags(core, core.registers[inst.reg1])
if value > 0xFFFFFFFF:
core.arith_overflow = True
[docs]class AND(_BITOP):
mnemonic = 'and'
opcode = DuckyOpcodes.AND
@staticmethod
[docs] def jit(core, inst):
regset = core.registers
if inst.immediate_flag == 1:
reg = inst.reg1
i = inst.sign_extend_immediate(core.LOGGER, inst)
def __jit_and():
regset[reg] = v = regset[reg] & i
core.arith_zero = v == 0
core.arith_overflow = False
core.arith_sign = (v & 0x80000000) != 0
return __jit_and
else:
reg1, reg2 = inst.reg1, inst.reg2
def __jit_and():
regset[reg1] = v = regset[reg1] & regset[reg2]
core.arith_zero = v == 0
core.arith_overflow = False
core.arith_sign = (v & 0x80000000) != 0
return __jit_and
[docs]class OR(_BITOP):
mnemonic = 'or'
opcode = DuckyOpcodes.OR
@staticmethod
[docs] def jit(core, inst):
regset = core.registers
if inst.immediate_flag == 1:
reg = inst.reg1
i = inst.sign_extend_immediate(core.LOGGER, inst)
def __jit_or():
regset[reg] = v = regset[reg] | i
core.arith_zero = v == 0
core.arith_overflow = False
core.arith_sign = (v & 0x80000000) != 0
return __jit_or
else:
reg1, reg2 = inst.reg1, inst.reg2
def __jit_or():
regset[reg1] = v = regset[reg1] | regset[reg2]
core.arith_zero = v == 0
core.arith_overflow = False
core.arith_sign = (v & 0x80000000) != 0
return __jit_or
[docs]class XOR(_BITOP):
mnemonic = 'xor'
opcode = DuckyOpcodes.XOR
@staticmethod
[docs] def jit(core, inst):
regset = core.registers
if inst.immediate_flag == 1:
reg = inst.reg1
i = inst.sign_extend_immediate(core.LOGGER, inst)
def __jit_xor():
regset[reg] = v = regset[reg] ^ i
core.arith_zero = v == 0
core.arith_overflow = False
core.arith_sign = (v & 0x80000000) != 0
return __jit_xor
else:
reg1, reg2 = inst.reg1, inst.reg2
def __jit_xor():
regset[reg1] = v = regset[reg1] ^ regset[reg2]
core.arith_zero = v == 0
core.arith_overflow = False
core.arith_sign = (v & 0x80000000) != 0
return __jit_xor
[docs]class SHL(_BITOP):
mnemonic = 'shiftl'
opcode = DuckyOpcodes.SHL
@staticmethod
[docs] def jit(core, inst):
regset = core.registers
if inst.immediate_flag == 1:
reg = inst.reg1
i = min(inst.sign_extend_immediate(core.LOGGER, inst), 32)
if i == 0:
def __jit_shiftl():
v = regset[reg]
core.arith_zero = v == 0
core.arith_overflow = False
core.arith_sign = (v & 0x80000000) != 0
return __jit_shiftl
elif i == 32:
def __jit_shiftl():
v = regset[reg] << i
regset[reg] = 0
core.arith_zero = True
core.arith_overflow = (v & ~0xFFFFFFFF) != 0
core.arith_sign = False
return __jit_shiftl
else:
def __jit_shiftl():
v = regset[reg] << i
regset[reg] = v % 4294967296
core.arith_zero = (v & 0xFFFFFFFF) == 0
core.arith_overflow = (v & ~0xFFFFFFFF) != 0
core.arith_sign = (v & 0x80000000) != 0
return __jit_shiftl
else:
reg1, reg2 = inst.reg1, inst.reg2
def __jit_shiftl():
i = min(regset[reg2], 32)
if i == 0:
v = regset[reg1]
core.arith_zero = v == 0
core.arith_overflow = False
core.arith_sign = (v & 0x80000000) != 0
elif i == 32:
v = regset[reg1] << i
regset[reg1] = 0
core.arith_zero = True
core.arith_overflow = (v & ~0xFFFFFFFF) != 0
core.arith_sign = False
else:
v = regset[reg1] << i
regset[reg1] = v % 4294967296
core.arith_zero = (v & 0xFFFFFFFF) == 0
core.arith_overflow = (v & ~0xFFFFFFFF) != 0
core.arith_sign = (v & 0x80000000) != 0
return __jit_shiftl
[docs]class SHR(_BITOP):
mnemonic = 'shiftr'
opcode = DuckyOpcodes.SHR
@staticmethod
[docs] def jit(core, inst):
regset = core.registers
if inst.immediate_flag == 1:
reg = inst.reg1
i = min(inst.sign_extend_immediate(core.LOGGER, inst), 32)
if i == 0:
def __jit_shiftr():
v = regset[reg]
core.arith_zero = v == 0
core.arith_overflow = False
core.arith_sign = (v & 0x80000000) != 0
return __jit_shiftr
elif i == 32:
def __jit_shiftr():
regset[reg] = 0
core.arith_zero = True
core.arith_overflow = core.arith_sign = False
return __jit_shiftr
else:
def __jit_shiftr():
regset[reg] = v = regset[reg] >> i
core.arith_zero = v == 0
core.arith_overflow = False
core.arith_sign = False
return __jit_shiftr
else:
reg1, reg2 = inst.reg1, inst.reg2
def __jit_shiftr():
i = min(regset[reg2], 32)
if i == 0:
v = regset[reg1]
core.arith_zero = v == 0
core.arith_overflow = False
core.arith_sign = (v & 0x80000000) != 0
elif i == 32:
regset[reg1] = 0
core.arith_zero = True
core.arith_overflow = core.arith_sign = False
else:
regset[reg1] = v = regset[reg1] >> i
core.arith_zero = v == 0
core.arith_overflow = False
core.arith_sign = False
return __jit_shiftr
[docs]class SHRS(_BITOP):
mnemonic = 'shiftrs'
opcode = DuckyOpcodes.SHRS
@staticmethod
[docs] def jit(core, inst):
regset = core.registers
if inst.immediate_flag == 1:
reg = inst.reg1
i = min(inst.sign_extend_immediate(core.LOGGER, inst), 32)
if i == 0:
def __jit_shrs():
v = regset[reg]
core.arith_zero = v == 0
core.arith_overflow = False
core.arith_sign = (v & 0x80000000) != 0
return __jit_shrs
else:
sign_mask = (((1 << i) - 1) << (32 - i))
def __jit_shrs():
x = regset[reg]
if x & 0x80000000 == 0:
v = x >> i
core.arith_sign = False
else:
v = (x >> i) | sign_mask
core.arith_sign = True
regset[reg] = v
core.arith_zero = v == 0
core.arith_overflow = False
return __jit_shrs
else:
reg1, reg2 = inst.reg1, inst.reg2
def __jit_shrs():
i = min(regset[reg2], 32)
if i == 0:
v = regset[reg1]
core.arith_zero = v == 0
core.arith_overflow = False
core.arith_sign = (v & 0x80000000) != 0
else:
x = regset[reg1]
if x & 0x80000000 == 0:
v = x >> i
core.arith_sign = False
else:
v = (x >> i) | (((1 << i) - 1) << (32 - i))
core.arith_sign = True
regset[reg1] = v
core.arith_zero = v == 0
core.arith_overflow = False
return __jit_shrs
[docs]class NOT(Descriptor_R):
mnemonic = 'not'
opcode = DuckyOpcodes.NOT
encoding = EncodingR
@staticmethod
[docs] def execute(core, inst):
core.registers[inst.reg1] = (~core.registers[inst.reg1]) % 4294967296
update_arith_flags(core, core.registers[inst.reg1])
#
# Memory load/store operations
#
[docs]class CAS(Descriptor):
mnemonic = 'cas'
operands = 'r,r,r'
opcode = DuckyOpcodes.CAS
encoding = EncodingA
@staticmethod
[docs] def assemble_operands(ctx, inst, operands):
ctx.encode(inst, 'reg1', 5, operands[0].operand)
ctx.encode(inst, 'reg2', 5, operands[1].operand)
ctx.encode(inst, 'reg3', 5, operands[2].operand)
@staticmethod
[docs] def disassemble_operands(logger, inst):
return [
REGISTER_NAMES[inst.reg1],
REGISTER_NAMES[inst.reg2],
REGISTER_NAMES[inst.reg3]
]
@staticmethod
[docs] def execute(core, inst):
core.arith_equal = False
addr = core.registers[inst.reg1]
actual_value = core.MEM_IN32(core.registers[inst.reg1])
core.DEBUG('CAS.execute: value=%s', UINT32_FMT(actual_value))
if actual_value == core.registers[inst.reg2]:
core.MEM_OUT32(addr, core.registers[inst.reg3])
core.arith_equal = True
else:
core.registers[inst.reg2] = actual_value
[docs]class _LOAD(Descriptor):
operands = 'r,a'
encoding = EncodingR
@staticmethod
[docs] def assemble_operands(ctx, inst, operands):
ctx.encode(inst, 'reg1', 5, operands[0].operand)
base, offset = operands[1].operand
ctx.encode(inst, 'reg2', 5, base.operand)
if offset.operand != 0:
ctx.encode(inst, 'immediate_flag', 1, 1)
ctx.encode(inst, 'immediate', 15, offset.operand)
@staticmethod
[docs] def disassemble_operands(logger, inst):
operands = [REGISTER_NAMES[inst.reg1]]
if inst.immediate_flag == 1:
operands.append('%s[%s]' % (REGISTER_NAMES[inst.reg2], inst.sign_extend_immediate(logger, inst)))
else:
operands.append(REGISTER_NAMES[inst.reg2])
return operands
@staticmethod
[docs] def execute(core, inst):
regset, reg = core.registers, inst.reg1
addr = RI_ADDR(core, inst, inst.reg2)
if inst.opcode == DuckyOpcodes.LW:
regset[reg] = core.MEM_IN32(addr)
elif inst.opcode == DuckyOpcodes.LS:
regset[reg] = core.MEM_IN16(addr)
else:
regset[reg] = core.MEM_IN8(addr)
update_arith_flags(core, regset[reg])
@staticmethod
[docs] def jit(core, inst):
regset, reg1, reg2 = core.registers, inst.reg1, inst.reg2
if inst.opcode == DuckyOpcodes.LW:
reader = core.MEM_IN32
if inst.immediate_flag == 1:
offset = inst.sign_extend_immediate(core.LOGGER, inst)
if offset == 0:
def __jit_lw():
regset[reg1] = v = reader(regset[reg2])
core.arith_zero = v == 0
core.arith_overflow = False
core.arith_sign = (v & 0x80000000) != 0
return __jit_lw
else:
def __jit_lw():
regset[reg1] = v = reader((regset[reg2] + offset) % 4294967296)
core.arith_zero = v == 0
core.arith_overflow = False
core.arith_sign = (v & 0x80000000) != 0
return __jit_lw
else:
def __jit_lw():
regset[reg1] = v = reader(regset[reg2])
core.arith_zero = v == 0
core.arith_overflow = False
core.arith_sign = (v & 0x80000000) != 0
return __jit_lw
elif inst.opcode == DuckyOpcodes.LS:
reader = core.MEM_IN16
if inst.immediate_flag == 1:
offset = inst.sign_extend_immediate(core.LOGGER, inst)
if offset == 0:
def __jit_ls():
regset[reg1] = v = reader(regset[reg2])
core.arith_zero = v == 0
core.arith_overflow = False
core.arith_sign = False
return __jit_ls
else:
def __jit_ls():
regset[reg1] = v = reader((regset[reg2] + offset) % 4294967296)
core.arith_zero = v == 0
core.arith_overflow = False
core.arith_sign = False
return __jit_ls
else:
def __jit_ls():
regset[reg1] = v = reader(regset[reg2])
core.arith_zero = v == 0
core.arith_overflow = False
core.arith_sign = False
return __jit_ls
elif inst.opcode == DuckyOpcodes.LB:
reader = core.MEM_IN8
if inst.immediate_flag == 1:
offset = inst.sign_extend_immediate(core.LOGGER, inst)
if offset == 0:
def __jit_lb():
regset[reg1] = v = reader(regset[reg2])
core.arith_zero = v == 0
core.arith_overflow = False
core.arith_sign = False
return __jit_lb
else:
def __jit_lb():
regset[reg1] = v = reader((regset[reg2] + offset) % 4294967296)
core.arith_zero = v == 0
core.arith_overflow = False
core.arith_sign = False
return __jit_lb
else:
def __jit_lb():
regset[reg1] = v = reader(regset[reg2])
core.arith_zero = v == 0
core.arith_overflow = False
core.arith_sign = False
return __jit_lb
return None
[docs]class _STORE(Descriptor):
operands = 'a,r'
encoding = EncodingR
@staticmethod
[docs] def assemble_operands(ctx, inst, operands):
ctx.encode(inst, 'reg2', 5, operands[1].operand)
base, offset = operands[0].operand
ctx.encode(inst, 'reg1', 5, base.operand)
if offset.operand != 0:
ctx.encode(inst, 'immediate_flag', 1, 1)
ctx.encode(inst, 'immediate', 15, offset.operand)
@staticmethod
[docs] def disassemble_operands(logger, inst):
operands = []
if inst.immediate_flag == 1:
operands.append('%s[%s]' % (REGISTER_NAMES[inst.reg1], inst.sign_extend_immediate(logger, inst)))
else:
operands.append(REGISTER_NAMES[inst.reg1])
operands.append(REGISTER_NAMES[inst.reg2])
return operands
@staticmethod
[docs] def execute(core, inst):
addr = RI_ADDR(core, inst, inst.reg1)
if inst.opcode == DuckyOpcodes.STW:
core.MEM_OUT32(addr, core.registers[inst.reg2])
elif inst.opcode == DuckyOpcodes.STS:
core.MEM_OUT16(addr, core.registers[inst.reg2] & 0xFFFF)
else:
core.MEM_OUT8(addr, core.registers[inst.reg2] & 0xFF)
@staticmethod
[docs] def jit(core, inst):
reg1, reg2 = inst.reg1, inst.reg2
regset = core.registers
if inst.opcode == DuckyOpcodes.STW:
writer = core.MEM_OUT32
if inst.immediate_flag == 1:
offset = inst.sign_extend_immediate(core.LOGGER, inst)
if offset == 0:
def __jit_stw():
writer(regset[reg1], regset[reg2])
return __jit_stw
else:
def __jit_stw():
writer((regset[reg1] + offset) % 4294967296, regset[reg2])
return __jit_stw
else:
def __jit_stw():
writer(regset[reg1], regset[reg2])
return __jit_stw
elif inst.opcode == DuckyOpcodes.STS:
writer = core.MEM_OUT16
if inst.immediate_flag == 1:
offset = inst.sign_extend_immediate(core.LOGGER, inst)
if offset == 0:
def __jit_sts():
writer(regset[reg1], regset[reg2])
return __jit_sts
else:
def __jit_sts():
writer((regset[reg1] + offset) % 4294967296, regset[reg2])
return __jit_sts
else:
def __jit_sts():
writer(regset[reg1], regset[reg2])
return __jit_sts
elif inst.opcode == DuckyOpcodes.STB:
writer = core.MEM_OUT8
if inst.immediate_flag == 1:
offset = inst.sign_extend_immediate(core.LOGGER, inst)
if offset == 0:
def __jit_stb():
writer(regset[reg1], regset[reg2] & 0xFF)
return __jit_stb
else:
def __jit_stb():
writer((regset[reg1] + offset) % 4294967296, regset[reg2] & 0xFF)
return __jit_stb
else:
def __jit_stb():
writer(regset[reg1], regset[reg2] & 0xFF)
return __jit_stb
return None
[docs]class _LOAD_IMM(Descriptor_R_I):
@classmethod
[docs] def load(cls, core, inst):
raise NotImplementedError('%s does not implement "load immediate" method' % cls.__name__)
@classmethod
[docs] def execute(cls, core, inst):
cls.load(core, inst)
update_arith_flags(core, core.registers[inst.reg])
[docs]class LW(_LOAD):
mnemonic = 'lw'
opcode = DuckyOpcodes.LW
[docs]class LS(_LOAD):
mnemonic = 'ls'
opcode = DuckyOpcodes.LS
[docs]class LB(_LOAD):
mnemonic = 'lb'
opcode = DuckyOpcodes.LB
[docs]class LI(_LOAD_IMM):
mnemonic = 'li'
opcode = DuckyOpcodes.LI
@classmethod
[docs] def load(cls, core, inst):
core.registers[inst.reg] = inst.sign_extend_immediate(core.LOGGER, inst)
@staticmethod
[docs] def jit(core, inst):
regset, reg = core.registers, inst.reg
i = inst.sign_extend_immediate(core.LOGGER, inst)
if i == 0:
def __jit_li():
regset[reg] = 0
core.arith_zero = True
core.arith_overflow = False
core.arith_sign = False
return __jit_li
else:
sign = (i & 0x80000000) != 0
def __jit_li():
regset[reg] = i
core.arith_zero = False
core.arith_overflow = False
core.arith_sign = sign
return __jit_li
[docs]class LIU(_LOAD_IMM):
mnemonic = 'liu'
opcode = DuckyOpcodes.LIU
@classmethod
[docs] def load(cls, core, inst):
regset, reg = core.registers, inst.reg
regset[reg] = (regset[reg] & 0xFFFF) | ((inst.sign_extend_immediate(core.LOGGER, inst) & 0xFFFF) << 16)
@staticmethod
[docs] def jit(core, inst):
regset, reg = core.registers, inst.reg
i = (inst.sign_extend_immediate(core.LOGGER, inst) & 0xFFFF) << 16
if i == 0:
def __jit_liu():
r = regset[reg]
regset[reg] = r = (r & 0xFFFF) | i
core.arith_zero = r == 0
core.arith_overflow = False
core.arith_sign = False
return __jit_liu
else:
def __jit_liu():
r = regset[reg]
regset[reg] = r = (r & 0xFFFF) | i
core.arith_zero = False
core.arith_overflow = False
core.arith_sign = (r & 0x80000000) != 0
return __jit_liu
[docs]class LA(_LOAD_IMM):
mnemonic = 'la'
opcode = DuckyOpcodes.LA
relative_address = True
@classmethod
[docs] def load(cls, core, inst):
core.registers[inst.reg] = (core.registers[Registers.IP] + inst.sign_extend_immediate(core.LOGGER, inst)) % 4294967296
@staticmethod
[docs] def jit(core, inst):
regset = core.registers
reg = inst.reg
offset = inst.sign_extend_immediate(core.LOGGER, inst)
ip = Registers.IP.value
if offset == 0:
def __jit_la():
regset[reg] = v = regset[ip]
core.arith_zero = v == 0
core.arith_overflow = False
core.arith_sign = (v & 0x80000000) != 0
return __jit_la
else:
def __jit_la():
v = regset[ip] + offset
regset[reg] = v % 4294967296
core.arith_zero = v == 0
core.arith_overflow = False
core.arith_sign = (v & 0x80000000) != 0
return __jit_la
[docs]class STW(_STORE):
mnemonic = 'stw'
opcode = DuckyOpcodes.STW
[docs]class STS(_STORE):
mnemonic = 'sts'
opcode = DuckyOpcodes.STS
[docs]class STB(_STORE):
mnemonic = 'stb'
opcode = DuckyOpcodes.STB
[docs]class MOV(Descriptor_R_R):
mnemonic = 'mov'
opcode = DuckyOpcodes.MOV
encoding = EncodingR
@staticmethod
[docs] def execute(core, inst):
core.registers[inst.reg1] = core.registers[inst.reg2]
@staticmethod
[docs] def jit(core, inst):
regset = core.registers
reg1, reg2 = inst.reg1, inst.reg2
def __jit_mov():
regset[reg1] = regset[reg2]
return __jit_mov
[docs]class SWP(Descriptor_R_R):
mnemonic = 'swp'
opcode = DuckyOpcodes.SWP
encoding = EncodingR
@staticmethod
[docs] def execute(core, inst):
regset = core.registers
regset[inst.reg1], regset[inst.reg2] = regset[inst.reg2], regset[inst.reg1]
@staticmethod
[docs] def jit(core, inst):
reg1, reg2 = inst.reg1, inst.reg2
regset = core.registers
def __jit_swp():
regset[reg1], regset[reg2] = regset[reg2], regset[reg1]
return __jit_swp
#
# Control instructions
#
[docs]class CTR(Descriptor_R_R):
mnemonic = 'ctr'
opcode = DuckyOpcodes.CTR
encoding = EncodingR
@staticmethod
[docs] def execute(core, inst):
core.registers[inst.reg1] = core.control_coprocessor.read(inst.reg2)
update_arith_flags(core, core.registers[inst.reg1])
@staticmethod
[docs] def jit(core, inst):
reg1 = inst.reg1
reg2 = inst.reg2
regset = core.registers
reader = core.control_coprocessor.read
def __jit_ctr():
regset[reg1] = v = reader(reg2)
core.arith_zero = v == 0
core.arith_overflow = False
core.arith_sign = (v & 0x80000000) != 0
return __jit_ctr
[docs]class CTW(Descriptor_R_R):
mnemonic = 'ctw'
opcode = DuckyOpcodes.CTW
encoding = EncodingR
@staticmethod
[docs] def execute(core, inst):
core.control_coprocessor.write(inst.reg1, core.registers[inst.reg2])
@staticmethod
[docs] def jit(core, inst):
reg1 = inst.reg1
reg2 = inst.reg2
regset = core.registers
writer = core.control_coprocessor.write
def __jit_ctw():
writer(reg1, regset[reg2])
return __jit_ctw
[docs]class FPTC(Descriptor):
mnemonic = 'fptc'
opcode = DuckyOpcodes.FPTC
encoding = EncodingI
@staticmethod
[docs] def execute(core, inst):
core.mmu.release_ptes()
@staticmethod
[docs] def jit(core, inst):
mmu = core.mmu
def __jit_fptc():
mmu.release_ptes()
return __jit_fptc
[docs]class DuckyInstructionSet(InstructionSet):
instruction_set_id = 0
opcodes = DuckyOpcodes
NOP(DuckyInstructionSet)
INT(DuckyInstructionSet)
IPI(DuckyInstructionSet)
RETINT(DuckyInstructionSet)
CALL(DuckyInstructionSet)
RET(DuckyInstructionSet)
CLI(DuckyInstructionSet)
STI(DuckyInstructionSet)
HLT(DuckyInstructionSet)
RST(DuckyInstructionSet)
IDLE(DuckyInstructionSet)
PUSH(DuckyInstructionSet)
POP(DuckyInstructionSet)
INC(DuckyInstructionSet)
DEC(DuckyInstructionSet)
ADD(DuckyInstructionSet)
SUB(DuckyInstructionSet)
CMP(DuckyInstructionSet)
J(DuckyInstructionSet)
AND(DuckyInstructionSet)
OR(DuckyInstructionSet)
XOR(DuckyInstructionSet)
NOT(DuckyInstructionSet)
SHL(DuckyInstructionSet)
SHR(DuckyInstructionSet)
SHRS(DuckyInstructionSet)
# Memory access
LW(DuckyInstructionSet)
LS(DuckyInstructionSet)
LB(DuckyInstructionSet)
LI(DuckyInstructionSet)
LIU(DuckyInstructionSet)
LA(DuckyInstructionSet)
STW(DuckyInstructionSet)
STS(DuckyInstructionSet)
STB(DuckyInstructionSet)
MOV(DuckyInstructionSet)
SWP(DuckyInstructionSet)
MUL(DuckyInstructionSet)
DIV(DuckyInstructionSet)
UDIV(DuckyInstructionSet)
MOD(DuckyInstructionSet)
CMPU(DuckyInstructionSet)
CAS(DuckyInstructionSet)
SIS(DuckyInstructionSet)
# Branching instructions
BE(DuckyInstructionSet)
BNE(DuckyInstructionSet)
BZ(DuckyInstructionSet)
BNZ(DuckyInstructionSet)
BO(DuckyInstructionSet)
BNO(DuckyInstructionSet)
BS(DuckyInstructionSet)
BNS(DuckyInstructionSet)
BG(DuckyInstructionSet)
BGE(DuckyInstructionSet)
BL(DuckyInstructionSet)
BLE(DuckyInstructionSet)
# SET* instructions
SETE(DuckyInstructionSet)
SETNE(DuckyInstructionSet)
SETZ(DuckyInstructionSet)
SETNZ(DuckyInstructionSet)
SETO(DuckyInstructionSet)
SETNO(DuckyInstructionSet)
SETS(DuckyInstructionSet)
SETNS(DuckyInstructionSet)
SETG(DuckyInstructionSet)
SETGE(DuckyInstructionSet)
SETL(DuckyInstructionSet)
SETLE(DuckyInstructionSet)
# SEL* instructions
SELE(DuckyInstructionSet)
SELNE(DuckyInstructionSet)
SELZ(DuckyInstructionSet)
SELNZ(DuckyInstructionSet)
SELO(DuckyInstructionSet)
SELNO(DuckyInstructionSet)
SELS(DuckyInstructionSet)
SELNS(DuckyInstructionSet)
SELG(DuckyInstructionSet)
SELGE(DuckyInstructionSet)
SELL(DuckyInstructionSet)
SELLE(DuckyInstructionSet)
LPM(DuckyInstructionSet)
# Control instructions
CTR(DuckyInstructionSet)
CTW(DuckyInstructionSet)
FPTC(DuckyInstructionSet)
DuckyInstructionSet.init()
INSTRUCTION_SETS = {
DuckyInstructionSet.instruction_set_id: DuckyInstructionSet
}
[docs]def get_instruction_set(i, exc = None):
exc = exc or InvalidInstructionSetError
if i not in INSTRUCTION_SETS:
raise exc(i)
return INSTRUCTION_SETS[i]