about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--miasm2/arch/x86/arch.py195
-rw-r--r--miasm2/arch/x86/sem.py72
-rw-r--r--miasm2/core/cpu.py3
-rw-r--r--test/arch/x86/arch.py36
4 files changed, 197 insertions, 109 deletions
diff --git a/miasm2/arch/x86/arch.py b/miasm2/arch/x86/arch.py
index 3f64c3c4..724f6b86 100644
--- a/miasm2/arch/x86/arch.py
+++ b/miasm2/arch/x86/arch.py
@@ -272,6 +272,8 @@ deref_ptr = Group(int_or_expr + COLON +
 
 PTR = Suppress('PTR')
 
+FAR = Suppress('FAR')
+
 
 BYTE = Literal('BYTE')
 WORD = Literal('WORD')
@@ -313,6 +315,9 @@ rmarg = Group(gpregs08.parser |
 rmarg |= deref_mem
 
 
+mem_far = FAR + deref_mem
+
+
 cl_or_imm = Group(r08_ecx.parser).setParseAction(getreg)
 cl_or_imm |= int_or_expr
 
@@ -583,7 +588,13 @@ class instruction_x86(instruction):
     def arg2str(expr, pos=None):
         if isinstance(expr, ExprId) or isinstance(expr, ExprInt):
             o = str(expr)
-        elif isinstance(expr, ExprMem):
+        elif ((isinstance(expr, ExprOp) and expr.op == 'far' and
+               isinstance(expr.args[0], ExprMem)) or
+              isinstance(expr, ExprMem)):
+            if isinstance(expr, ExprOp):
+                prefix, expr = "FAR ", expr.args[0]
+            else:
+                prefix = ""
             sz = SIZE2MEMPREFIX[expr.size]
             segm = ""
             if expr.is_op_segm():
@@ -595,7 +606,7 @@ class instruction_x86(instruction):
                 s = str(expr).replace('(', '').replace(')', '')
             else:
                 s = str(expr)
-            o = sz + ' PTR %s[%s]' % (segm, s)
+            o = prefix + sz + ' PTR %s[%s]' % (segm, s)
         elif isinstance(expr, ExprOp) and expr.op == 'segm':
             o = "%s:%s" % (expr.args[0], expr.args[1])
         else:
@@ -2039,6 +2050,42 @@ class x86_rm_mem(x86_rm_arg):
             return None, None
         return start, stop
 
+
+class x86_rm_mem_far(x86_rm_arg):
+    parser = mem_far
+    def fromstring(self, s, parser_result=None):
+        self.expr = None
+        start, stop = super(x86_rm_mem_far, self).fromstring(s, parser_result)
+        if not isinstance(self.expr, ExprMem):
+            return None, None
+        self.expr = ExprOp('far', self.expr)
+        return start, stop
+
+    def decode(self, v):
+        ret = super(x86_rm_mem_far, self).decode(v)
+        if not ret:
+            return ret
+        if isinstance(self.expr, m2_expr.ExprMem):
+            self.expr = ExprOp('far', self.expr)
+        return True
+
+    def encode(self):
+        if not (isinstance(self.expr, m2_expr.ExprOp) and
+                self.expr.op == 'far'):
+            raise StopIteration
+
+        expr = self.expr.args[0]
+        if isinstance(expr, ExprInt):
+            raise StopIteration
+        p = self.parent
+        admode = p.v_admode()
+        mode = expr.size
+        v_cand, segm, ok = expr2modrm(expr, p, 1)
+        if segm:
+            p.g2.value = segm2enc[segm]
+        for x in self.gen_cand(v_cand, admode):
+            yield x
+
 class x86_rm_w8(x86_rm_arg):
 
     def decode(self, v):
@@ -3143,6 +3190,7 @@ rm_arg_m80 = bs(l=0, cls=(x86_rm_m80,), fname='rmarg')
 rm_arg_m16 = bs(l=0, cls=(x86_rm_m16,), fname='rmarg')
 
 rm_mem = bs(l=0, cls=(x86_rm_mem,), fname='rmarg')
+rm_mem_far = bs(l=0, cls=(x86_rm_mem_far,), fname='rmarg')
 
 rm_arg_mm = bs(l=0, cls=(x86_rm_mm,), fname='rmarg')
 rm_arg_mm_m64 = bs(l=0, cls=(x86_rm_mm_m64,), fname='rmarg')
@@ -3156,6 +3204,74 @@ rm_arg_xmm_reg = bs(l=0, cls=(x86_rm_xmm_reg,), fname='rmarg')
 swapargs = bs_swapargs(l=1, fname="swap", mn_mod=range(1 << 1))
 
 
+class bs_op_mode(bsi):
+
+    def decode(self, v):
+        opmode = self.parent.v_opmode()
+        return opmode == self.mode
+
+
+class bs_ad_mode(bsi):
+
+    def decode(self, v):
+        admode = self.parent.v_admode()
+        return admode == self.mode
+
+
+class bs_op_mode_no64(bsi):
+
+    def encode(self):
+        if self.parent.mode == 64:
+            return False
+        return super(bs_op_mode_no64, self).encode()
+
+    def decode(self, v):
+        if self.parent.mode == 64:
+            return False
+        opmode = self.parent.v_opmode()
+        return opmode == self.mode
+
+
+class bs_op_mode64(bsi):
+    def encode(self):
+        if self.parent.mode != 64:
+            return False
+        return super(bs_op_mode64, self).encode()
+
+    def decode(self, v):
+        if self.parent.mode != 64:
+            return False
+        return True
+
+class bs_op_modeno64(bsi):
+    def encode(self):
+        if self.parent.mode == 64:
+            return False
+        return super(bs_op_modeno64, self).encode()
+
+    def decode(self, v):
+        if self.parent.mode == 64:
+            return False
+        return True
+
+
+
+bs_opmode16 = bs(l=0, cls=(bs_op_mode,), mode = 16, fname="fopmode")
+bs_opmode32 = bs(l=0, cls=(bs_op_mode,), mode = 32, fname="fopmode")
+bs_opmode64 = bs(l=0, cls=(bs_op_mode,), mode = 64, fname="fopmode")
+
+
+bs_admode16 = bs(l=0, cls=(bs_ad_mode,), mode = 16, fname="fadmode")
+bs_admode32 = bs(l=0, cls=(bs_ad_mode,), mode = 32, fname="fadmode")
+bs_admode64 = bs(l=0, cls=(bs_ad_mode,), mode = 64, fname="fadmode")
+
+bs_opmode16_no64 = bs(l=0, cls=(bs_op_mode_no64,), mode = 16, fname="fopmode")
+bs_opmode32_no64 = bs(l=0, cls=(bs_op_mode_no64,), mode = 32, fname="fopmode")
+
+bs_mode64 = bs(l=0, cls=(bs_op_mode64,))
+bs_modeno64 = bs(l=0, cls=(bs_op_modeno64,))
+
+
 cond_list = ["O", "NO", "B", "AE",
              "Z", "NZ", "BE", "A",
              "S", "NS", "PE", "NP",
@@ -3229,76 +3345,9 @@ addop("bts", [bs8(0x0f), bs8(0xba)] + rmmod(d5) + [u08])
 
 addop("call", [bs8(0xe8), rel_off])
 addop("call", [bs8(0xff), stk] + rmmod(d2))
-addop("call", [bs8(0xff), stk] + rmmod(d3, modrm=mod_mem))
-addop("call", [bs8(0x9a), moff, msegoff])
-
-
-class bs_op_mode(bsi):
-
-    def decode(self, v):
-        opmode = self.parent.v_opmode()
-        return opmode == self.mode
-
-
-class bs_ad_mode(bsi):
-
-    def decode(self, v):
-        admode = self.parent.v_admode()
-        return admode == self.mode
-
-
-class bs_op_mode_no64(bsi):
-
-    def encode(self):
-        if self.parent.mode == 64:
-            return False
-        return super(bs_op_mode_no64, self).encode()
-
-    def decode(self, v):
-        if self.parent.mode == 64:
-            return False
-        opmode = self.parent.v_opmode()
-        return opmode == self.mode
-
+addop("call", [bs8(0xff), stk] + rmmod(d3, rm_arg_x=rm_mem_far, modrm=mod_mem))
+addop("call", [bs8(0x9a), bs_modeno64, moff, msegoff])
 
-class bs_op_mode64(bsi):
-    def encode(self):
-        if self.parent.mode != 64:
-            return False
-        return super(bs_op_mode64, self).encode()
-
-    def decode(self, v):
-        if self.parent.mode != 64:
-            return False
-        return True
-
-class bs_op_modeno64(bsi):
-    def encode(self):
-        if self.parent.mode == 64:
-            return False
-        return super(bs_op_modeno64, self).encode()
-
-    def decode(self, v):
-        if self.parent.mode == 64:
-            return False
-        return True
-
-
-
-bs_opmode16 = bs(l=0, cls=(bs_op_mode,), mode = 16, fname="fopmode")
-bs_opmode32 = bs(l=0, cls=(bs_op_mode,), mode = 32, fname="fopmode")
-bs_opmode64 = bs(l=0, cls=(bs_op_mode,), mode = 64, fname="fopmode")
-
-
-bs_admode16 = bs(l=0, cls=(bs_ad_mode,), mode = 16, fname="fadmode")
-bs_admode32 = bs(l=0, cls=(bs_ad_mode,), mode = 32, fname="fadmode")
-bs_admode64 = bs(l=0, cls=(bs_ad_mode,), mode = 64, fname="fadmode")
-
-bs_opmode16_no64 = bs(l=0, cls=(bs_op_mode_no64,), mode = 16, fname="fopmode")
-bs_opmode32_no64 = bs(l=0, cls=(bs_op_mode_no64,), mode = 32, fname="fopmode")
-
-bs_mode64 = bs(l=0, cls=(bs_op_mode64,))
-bs_modeno64 = bs(l=0, cls=(bs_op_modeno64,))
 
 addop("cbw", [bs8(0x98), bs_opmode16])
 addop("cwde", [bs8(0x98), bs_opmode32])
@@ -3551,9 +3600,9 @@ addop("jmp", [bs8(0xeb), rel_off08])
 addop("jmp", [bs8(0xe9), rel_off])
 # TODO XXX replace stk force64?
 addop("jmp", [bs8(0xff), stk] + rmmod(d4))
-addop("jmpf", [bs8(0xea), moff, msegoff])
+addop("jmp", [bs8(0xea), bs_modeno64, moff, msegoff])
 
-addop("jmpf", [bs8(0xff)] + rmmod(d5))
+addop("jmp", [bs8(0xff)] + rmmod(d5, rm_arg_x=rm_mem_far, modrm=mod_mem))
 
 addop("lahf", [bs8(0x9f)])
 addop("lar", [bs8(0x0f), bs8(0x02)] + rmmod(rmreg))
diff --git a/miasm2/arch/x86/sem.py b/miasm2/arch/x86/sem.py
index c2d84253..5148bd28 100644
--- a/miasm2/arch/x86/sem.py
+++ b/miasm2/arch/x86/sem.py
@@ -1149,14 +1149,24 @@ def call(ir, instr, dst):
     myesp = mRSP[instr.mode][:opmode]
     n = m2_expr.ExprId(ir.get_next_label(instr), ir.IRDst.size)
 
-    if (isinstance(dst, m2_expr.ExprOp) and dst.op == "segm"):
-        # call far
-        if instr.mode != 16:
-            raise NotImplementedError('add 32 bit support!')
-        segm = dst.args[0]
-        base = dst.args[1]
-        m1 = segm.zeroExtend(CS.size)
-        m2 = base.zeroExtend(meip.size)
+    if isinstance(dst, m2_expr.ExprOp):
+        if dst.op == "segm":
+            # Far call segm:addr
+            if instr.mode not in [16, 32]:
+                raise RuntimeError('not supported')
+            segm = dst.args[0]
+            base = dst.args[1]
+            m1 = segm.zeroExtend(CS.size)
+            m2 = base.zeroExtend(meip.size)
+        elif dst.op == "far":
+            # Far call far [eax]
+            addr = dst.args[0].arg
+            m1 = m2_expr.ExprMem(addr, CS.size)
+            m2 = m2_expr.ExprMem(addr + m2_expr.ExprInt_from(addr, 2),
+                                 meip.size)
+        else:
+            raise RuntimeError("bad call operator")
+
         e.append(m2_expr.ExprAff(CS, m1))
         e.append(m2_expr.ExprAff(meip, m2))
 
@@ -1274,33 +1284,34 @@ def enter(ir, instr, a, b):
 def jmp(ir, instr, dst):
     e = []
     meip = mRIP[ir.IRDst.size]
-    e.append(m2_expr.ExprAff(meip, dst))  # dst.zeroExtend(ir.IRDst.size)))
-    e.append(m2_expr.ExprAff(ir.IRDst, dst))  # dst.zeroExtend(ir.IRDst.size)))
 
-    if isinstance(dst, m2_expr.ExprMem):
-        dst = meip
-    return e, []
+    if isinstance(dst, m2_expr.ExprOp):
+        if dst.op == "segm":
+            # Far jmp segm:addr
+            segm = dst.args[0]
+            base = dst.args[1]
+            m1 = segm.zeroExtend(CS.size)
+            m2 = base.zeroExtend(meip.size)
+        elif dst.op == "far":
+            # Far jmp far [eax]
+            addr = dst.args[0].arg
+            m1 = m2_expr.ExprMem(addr, CS.size)
+            m2 = m2_expr.ExprMem(addr + m2_expr.ExprInt_from(addr, 2),
+                                 meip.size)
+        else:
+            raise RuntimeError("bad jmp operator")
 
+        e.append(m2_expr.ExprAff(CS, m1))
+        e.append(m2_expr.ExprAff(meip, m2))
+        e.append(m2_expr.ExprAff(ir.IRDst, m2))
 
-def jmpf(ir, instr, a):
-    e = []
-    meip = mRIP[ir.IRDst.size]
-    s = instr.mode
-    if (isinstance(a, m2_expr.ExprOp) and a.op == "segm"):
-        segm = a.args[0]
-        base = a.args[1]
-        m1 = segm.zeroExtend(
-            CS.size)  # m2_expr.ExprMem(m2_expr.ExprOp('segm', segm, base), 16)
-        m2 = base.zeroExtend(meip.size)
-                             # m2_expr.ExprMem(m2_expr.ExprOp('segm', segm,
-                             # base + m2_expr.ExprInt_from(base, 2)), s)
     else:
-        m1 = m2_expr.ExprMem(a, 16)
-        m2 = m2_expr.ExprMem(a + m2_expr.ExprInt_from(a, 2), meip.size)
+        # Classic jmp
+        e.append(m2_expr.ExprAff(meip, dst))
+        e.append(m2_expr.ExprAff(ir.IRDst, dst))
 
-    e.append(m2_expr.ExprAff(CS, m1))
-    e.append(m2_expr.ExprAff(meip, m2))
-    e.append(m2_expr.ExprAff(ir.IRDst, m2))
+        if isinstance(dst, m2_expr.ExprMem):
+            dst = meip
     return e, []
 
 
@@ -4061,7 +4072,6 @@ mnemo_func = {'mov': mov,
               'leave': leave,
               'enter': enter,
               'jmp': jmp,
-              'jmpf': jmpf,
               'jz': jz,
               'je': jz,
               'jcxz': jcxz,
diff --git a/miasm2/core/cpu.py b/miasm2/core/cpu.py
index d304108d..8195f920 100644
--- a/miasm2/core/cpu.py
+++ b/miasm2/core/cpu.py
@@ -262,7 +262,8 @@ def extract_ast_core(v, my_id2expr, my_int2expr):
         size = sizes.pop()
         my_int2expr = lambda x: m2_expr.ExprInt(x, size)
     else:
-        raise ValueError('multiple sizes in ids')
+        # Multiple sizes in ids
+        raise StopIteration
     e = ast_raw2expr(ast_tokens, my_id2expr, my_int2expr)
     return e
 
diff --git a/test/arch/x86/arch.py b/test/arch/x86/arch.py
index dfe4ef91..6d20d473 100644
--- a/test/arch/x86/arch.py
+++ b/test/arch/x86/arch.py
@@ -767,20 +767,41 @@ reg_tests = [
      "e830221100"),
     (m32, "00000000    CALL       DWORD PTR [EAX]",
      "ff10"),
+    (m32, "00000000    CALL       EAX",
+     "ffd0"),
+    (m32, "00000000    CALL       DWORD PTR [EAX+EBX]",
+     "ff1403"),
+    (m32, "00000000    CALL       DWORD PTR [EAX+EBX+0x11223344]",
+     "ff941844332211"),
+
+
+
+
+
     (m64, "00000000    CALL       QWORD PTR [RAX]",
      "ff10"),
-
     (m32, "00000000    CALL       0x6655:0x44332211",
      "9a112233445566"),
     (m32, "00000000    CALL       0x6655:0xFF332211",
      "9a112233FF5566"),
 
-    (m32, "00000000    CALL       DWORD PTR [0xFFFFFFA3]",
+    (m64, "00000000    CALL       QWORD PTR [RAX+RBX]",
+     "ff1403"),
+    (m64, "00000000    CALL       QWORD PTR [RAX+RBX+0x11223344]",
+     "ff941844332211"),
+
+
+    (m32, "00000000    CALL       FAR DWORD PTR [EAX]",
+     "ff18"),
+    (m32, "00000000    CALL       FAR DWORD PTR [EAX+EBX]",
+     "ff1c03"),
+    (m32, "00000000    CALL       FAR DWORD PTR [EAX+EBX+0x11223344]",
+     "ff9c1844332211"),
+    (m32, "00000000    CALL       FAR DWORD PTR [0xFFFFFFA3]",
      "FF1DA3FFFFFF"),
-    (m64, "00000000    CALL       QWORD PTR [RIP+0xFFFFFFFFFFFFFFA3]",
+    (m64, "00000000    CALL       FAR QWORD PTR [RIP+0xFFFFFFFFFFFFFFA3]",
      "FF1DA3FFFFFF"),
 
-
     (m16, "00000000    CBW",
      "98"),
     (m16, "00000000    CWDE",
@@ -2419,6 +2440,13 @@ reg_tests = [
     (m64, "00000000    JMP        RDX",
      "FFE2"),
 
+    (m32, "00000000    JMP        FAR DWORD PTR [EAX]",
+     "FF28"),
+    (m64, "00000000    JMP        FAR DWORD PTR [RAX]",
+     "FF28"),
+    (m32, "00000000    JMP        0x6655:0x44332211",
+     "EA112233445566"),
+
     (m32, "00000000    XGETBV",
      "0f01d0"),