about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--miasm2/analysis/dse.py3
-rw-r--r--miasm2/arch/x86/ctype.py12
-rw-r--r--miasm2/arch/x86/jit.py9
-rw-r--r--miasm2/arch/x86/sem.py115
-rw-r--r--miasm2/core/objc.py54
-rw-r--r--miasm2/expression/simplifications_common.py11
-rw-r--r--miasm2/jitter/vm_mngr_py.c2
-rwxr-xr-xtest/arch/x86/unit/mn_pushpop.py195
-rw-r--r--test/expression/simplifications.py5
9 files changed, 335 insertions, 71 deletions
diff --git a/miasm2/analysis/dse.py b/miasm2/analysis/dse.py
index 7fdc5035..56ed3292 100644
--- a/miasm2/analysis/dse.py
+++ b/miasm2/analysis/dse.py
@@ -185,6 +185,9 @@ class DSEEngine(object):
         self.jitter.jit.set_options(max_exec_per_call=1, jit_maxline=1)
         self.jitter.exec_cb = self.callback
 
+        # Clean jit cache to avoid multi-line basic blocks already jitted
+        self.jitter.jit.lbl2jitbloc.clear()
+
     def attach(self, emulator):
         """Attach the DSE to @emulator
         @emulator: jitload (or API equivalent) instance"""
diff --git a/miasm2/arch/x86/ctype.py b/miasm2/arch/x86/ctype.py
index 0d8cd924..5e16f945 100644
--- a/miasm2/arch/x86/ctype.py
+++ b/miasm2/arch/x86/ctype.py
@@ -1,10 +1,12 @@
-from miasm2.core.objc import CLeafTypes, ObjCDecl
+from miasm2.core.objc import CLeafTypes, ObjCDecl, PADDING_TYPE_NAME
 from miasm2.core.ctypesmngr import CTypeId, CTypePtr
 
 
 class CTypeAMD64_unk(CLeafTypes):
     """Define C types sizes/alignement for x86_64 architecture"""
 
+    obj_pad = ObjCDecl(PADDING_TYPE_NAME, 1, 1) # __padding__ is size 1/align 1
+
     obj_char = ObjCDecl("char", 1, 1)
     obj_short = ObjCDecl("short", 2, 2)
     obj_int = ObjCDecl("int", 4, 4)
@@ -25,6 +27,8 @@ class CTypeAMD64_unk(CLeafTypes):
 
     def __init__(self):
         self.types = {
+            CTypeId(PADDING_TYPE_NAME): self.obj_pad,
+
             CTypeId('char'): self.obj_char,
             CTypeId('short'): self.obj_short,
             CTypeId('int'): self.obj_int,
@@ -68,7 +72,9 @@ class CTypeAMD64_unk(CLeafTypes):
 
 
 class CTypeX86_unk(CLeafTypes):
-    """Define C types sizes/alignement for x86_64 architecture"""
+    """Define C types sizes/alignement for x86_32 architecture"""
+
+    obj_pad = ObjCDecl(PADDING_TYPE_NAME, 1, 1) # __padding__ is size 1/align 1
 
     obj_char = ObjCDecl("char", 1, 1)
     obj_short = ObjCDecl("short", 2, 2)
@@ -90,6 +96,8 @@ class CTypeX86_unk(CLeafTypes):
 
     def __init__(self):
         self.types = {
+            CTypeId(PADDING_TYPE_NAME): self.obj_pad,
+
             CTypeId('char'): self.obj_char,
             CTypeId('short'): self.obj_short,
             CTypeId('int'): self.obj_int,
diff --git a/miasm2/arch/x86/jit.py b/miasm2/arch/x86/jit.py
index 9acab5ed..d39f1f38 100644
--- a/miasm2/arch/x86/jit.py
+++ b/miasm2/arch/x86/jit.py
@@ -80,6 +80,15 @@ class jitter_x86_32(jitter):
     def ir_archbloc_fix_regs_for_mode(self, irblock, attrib=64):
         return self.orig_irbloc_fix_regs_for_mode(irblock, 64)
 
+    def push_uint16_t(self, value):
+        self.cpu.ESP -= self.ir_arch.sp.size / 8
+        self.vm.set_mem(self.cpu.ESP, pck16(value))
+
+    def pop_uint16_t(self):
+        value = upck16(self.vm.get_mem(self.cpu.ESP, self.ir_arch.sp.size / 8))
+        self.cpu.ESP += self.ir_arch.sp.size / 8
+        return value
+
     def push_uint32_t(self, value):
         self.cpu.ESP -= self.ir_arch.sp.size / 8
         self.vm.set_mem(self.cpu.ESP, pck32(value))
diff --git a/miasm2/arch/x86/sem.py b/miasm2/arch/x86/sem.py
index ca5b3f8d..b3dfb3ef 100644
--- a/miasm2/arch/x86/sem.py
+++ b/miasm2/arch/x86/sem.py
@@ -693,17 +693,14 @@ def push_gen(ir, instr, src, size):
         raise ValueError('bad size stacker!')
     if src.size < size:
         src = src.zeroExtend(size)
-    elif src.size == size:
-        pass
-    else:
-        raise ValueError('strange arg size')
+    off_size = src.size
 
     sp = mRSP[instr.mode]
-    new_sp = sp - m2_expr.ExprInt(size / 8, sp.size)
+    new_sp = sp - m2_expr.ExprInt(off_size / 8, sp.size)
     e.append(m2_expr.ExprAff(sp, new_sp))
     if ir.do_stk_segm:
         new_sp = m2_expr.ExprOp('segm', SS, new_sp)
-    e.append(m2_expr.ExprAff(ir.ExprMem(new_sp, size),
+    e.append(m2_expr.ExprAff(ir.ExprMem(new_sp, off_size),
                              src))
     return e, []
 
@@ -722,7 +719,7 @@ def pop_gen(ir, instr, src, size):
         raise ValueError('bad size stacker!')
 
     sp = mRSP[instr.mode]
-    new_sp = sp + m2_expr.ExprInt(size / 8, sp.size)
+    new_sp = sp + m2_expr.ExprInt(src.size / 8, sp.size)
     # don't generate ESP incrementation on POP ESP
     if src != ir.sp:
         e.append(m2_expr.ExprAff(sp, new_sp))
@@ -937,25 +934,34 @@ def cmps(ir, instr, size):
     lbl_df_1 = m2_expr.ExprId(ir.gen_label(), ir.IRDst.size)
     lbl_next = m2_expr.ExprId(ir.get_next_label(instr), ir.IRDst.size)
 
-    s = instr.v_admode()
-    a = ir.ExprMem(mRDI[instr.mode][:s], size)
-    b = ir.ExprMem(mRSI[instr.mode][:s], size)
+    src1 = mRSI[instr.mode][:instr.v_admode()]
+    src2 = mRDI[instr.mode][:instr.v_admode()]
+
+    if ir.do_str_segm:
+        if instr.additional_info.g2.value:
+            raise NotImplementedError("add segm support")
+        src1_sgm = m2_expr.ExprOp('segm', DS, src1)
+        src2_sgm = m2_expr.ExprOp('segm', ES, src2)
+    else:
+        src1_sgm = src1
+        src2_sgm = src2
+
+    offset = m2_expr.ExprInt(size / 8, src1.size)
+
+    e, _ = l_cmp(ir, instr,
+                 ir.ExprMem(src1_sgm, size),
+                 ir.ExprMem(src2_sgm, size))
 
-    e, _ = l_cmp(ir, instr, b, a)
 
     e0 = []
-    e0.append(m2_expr.ExprAff(a.arg,
-                              a.arg + m2_expr.ExprInt(size / 8, a.arg.size)))
-    e0.append(m2_expr.ExprAff(b.arg,
-                              b.arg + m2_expr.ExprInt(size / 8, b.arg.size)))
+    e0.append(m2_expr.ExprAff(src1, src1 + offset))
+    e0.append(m2_expr.ExprAff(src2, src2 + offset))
     e0.append(m2_expr.ExprAff(ir.IRDst, lbl_next))
     e0 = IRBlock(lbl_df_0.name, [AssignBlock(e0, instr)])
 
     e1 = []
-    e1.append(m2_expr.ExprAff(a.arg,
-                              a.arg - m2_expr.ExprInt(size / 8, a.arg.size)))
-    e1.append(m2_expr.ExprAff(b.arg,
-                              b.arg - m2_expr.ExprInt(size / 8, b.arg.size)))
+    e1.append(m2_expr.ExprAff(src1, src1 - offset))
+    e1.append(m2_expr.ExprAff(src2, src2 - offset))
     e1.append(m2_expr.ExprAff(ir.IRDst, lbl_next))
     e1 = IRBlock(lbl_df_1.name, [AssignBlock(e1, instr)])
 
@@ -969,20 +975,28 @@ def scas(ir, instr, size):
     lbl_df_1 = m2_expr.ExprId(ir.gen_label(), ir.IRDst.size)
     lbl_next = m2_expr.ExprId(ir.get_next_label(instr), ir.IRDst.size)
 
-    s = instr.v_admode()
-    a = ir.ExprMem(mRDI[instr.mode][:s], size)
+    src = mRDI[instr.mode][:instr.v_admode()]
 
-    e, extra = l_cmp(ir, instr, mRAX[instr.mode][:size], a)
+    if ir.do_str_segm:
+        if instr.additional_info.g2.value:
+            raise NotImplementedError("add segm support")
+        src_sgm = m2_expr.ExprOp('segm', ES, src)
+    else:
+        src_sgm = src
+
+    offset = m2_expr.ExprInt(size / 8, src.size)
+    e, extra = l_cmp(ir, instr,
+                     mRAX[instr.mode][:size],
+                     ir.ExprMem(src_sgm, size))
 
     e0 = []
-    e0.append(m2_expr.ExprAff(a.arg,
-                              a.arg + m2_expr.ExprInt(size / 8, a.arg.size)))
+    e0.append(m2_expr.ExprAff(src, src + offset))
+
     e0.append(m2_expr.ExprAff(ir.IRDst, lbl_next))
     e0 = IRBlock(lbl_df_0.name, [AssignBlock(e0, instr)])
 
     e1 = []
-    e1.append(m2_expr.ExprAff(a.arg,
-                              a.arg - m2_expr.ExprInt(size / 8, a.arg.size)))
+    e1.append(m2_expr.ExprAff(src, src - offset))
     e1.append(m2_expr.ExprAff(ir.IRDst, lbl_next))
     e1 = IRBlock(lbl_df_1.name, [AssignBlock(e1, instr)])
 
@@ -1081,12 +1095,11 @@ pa_regs = [
 
 def pusha_gen(ir, instr, size):
     e = []
+    cur_sp = mRSP[instr.mode]
     for i, reg in enumerate(pa_regs):
-        stk_ptr = mRSP[instr.mode] + \
-            m2_expr.ExprInt(-(reg[size].size / 8) * (i + 1), instr.mode)
-        e.append(m2_expr.ExprAff(ir.ExprMem(
-            stk_ptr, reg[size].size), reg[size]))
-    e.append(m2_expr.ExprAff(mRSP[instr.mode], stk_ptr))
+        stk_ptr = cur_sp + m2_expr.ExprInt(-(size / 8) * (i + 1), instr.mode)
+        e.append(m2_expr.ExprAff(ir.ExprMem(stk_ptr, size), reg[size]))
+    e.append(m2_expr.ExprAff(cur_sp, stk_ptr))
     return e, []
 
 
@@ -1100,16 +1113,15 @@ def pushad(ir, instr):
 
 def popa_gen(ir, instr, size):
     e = []
+    cur_sp = mRSP[instr.mode]
     for i, reg in enumerate(reversed(pa_regs)):
         if reg == mRSP:
             continue
-        stk_ptr = mRSP[instr.mode] + \
-            m2_expr.ExprInt((reg[size].size / 8) * i, instr.mode)
-        e.append(m2_expr.ExprAff(reg[size], ir.ExprMem(stk_ptr, instr.mode)))
+        stk_ptr = cur_sp + m2_expr.ExprInt((size / 8) * i, instr.mode)
+        e.append(m2_expr.ExprAff(reg[size], ir.ExprMem(stk_ptr, size)))
 
-    stk_ptr = mRSP[instr.mode] + \
-        m2_expr.ExprInt((instr.mode / 8) * (i + 1), instr.mode)
-    e.append(m2_expr.ExprAff(mRSP[instr.mode], stk_ptr))
+    stk_ptr = cur_sp + m2_expr.ExprInt((size / 8) * (i + 1), instr.mode)
+    e.append(m2_expr.ExprAff(cur_sp, stk_ptr))
 
     return e, []
 
@@ -1726,29 +1738,34 @@ def movs(ir, instr, size):
     lbl_df_1 = m2_expr.ExprId(ir.gen_label(), ir.IRDst.size)
     lbl_next = m2_expr.ExprId(ir.get_next_label(instr), ir.IRDst.size)
 
-    a = mRDI[instr.mode][:instr.v_admode()]
-    b = mRSI[instr.mode][:instr.v_admode()]
+    dst = mRDI[instr.mode][:instr.v_admode()]
+    src = mRSI[instr.mode][:instr.v_admode()]
 
     e = []
-    src = b
-    dst = a
     if ir.do_str_segm:
         if instr.additional_info.g2.value:
             raise NotImplementedError("add segm support")
-        src = m2_expr.ExprOp('segm', DS, src)
-        dst = m2_expr.ExprOp('segm', ES, dst)
-    e.append(m2_expr.ExprAff(ir.ExprMem(dst, size),
-                             ir.ExprMem(src, size)))
+        src_sgm = m2_expr.ExprOp('segm', DS, src)
+        dst_sgm = m2_expr.ExprOp('segm', ES, dst)
+
+    else:
+        src_sgm = src
+        dst_sgm = dst
+
+    offset = m2_expr.ExprInt(size / 8, src.size)
+
+    e.append(m2_expr.ExprAff(ir.ExprMem(dst_sgm, size),
+                             ir.ExprMem(src_sgm, size)))
 
     e0 = []
-    e0.append(m2_expr.ExprAff(a, a + m2_expr.ExprInt(size / 8, a.size)))
-    e0.append(m2_expr.ExprAff(b, b + m2_expr.ExprInt(size / 8, b.size)))
+    e0.append(m2_expr.ExprAff(src, src + offset))
+    e0.append(m2_expr.ExprAff(dst, dst + offset))
     e0.append(m2_expr.ExprAff(ir.IRDst, lbl_next))
     e0 = IRBlock(lbl_df_0.name, [AssignBlock(e0, instr)])
 
     e1 = []
-    e1.append(m2_expr.ExprAff(a, a - m2_expr.ExprInt(size / 8, a.size)))
-    e1.append(m2_expr.ExprAff(b, b - m2_expr.ExprInt(size / 8, b.size)))
+    e1.append(m2_expr.ExprAff(src, src - offset))
+    e1.append(m2_expr.ExprAff(dst, dst - offset))
     e1.append(m2_expr.ExprAff(ir.IRDst, lbl_next))
     e1 = IRBlock(lbl_df_1.name, [AssignBlock(e1, instr)])
 
diff --git a/miasm2/core/objc.py b/miasm2/core/objc.py
index 9ae16291..917d0ea9 100644
--- a/miasm2/core/objc.py
+++ b/miasm2/core/objc.py
@@ -15,6 +15,8 @@ from miasm2.core.ctypesmngr import CTypeUnion, CTypeStruct, CTypeId, CTypePtr,\
     CTypeArray, CTypeOp, CTypeSizeof, CTypeEnum, CTypeFunc, CTypeEllipsis
 
 
+PADDING_TYPE_NAME = "___padding___"
+
 class ObjC(object):
     """Generic ObjC"""
 
@@ -618,14 +620,18 @@ class CTypeAnalyzer(ExprReducer):
     Return the C type(s) of a native Miasm expression
     """
 
-    def __init__(self, expr_types, types_mngr):
+    def __init__(self, expr_types, types_mngr, enforce_strict_access=True):
         """Init TypeAnalyzer
         @expr_types: a dictionnary linking ID names to their types
         @types_mngr: types manager
+        @enforce_strict_access: If false, get type even on expression
+        pointing to a middle of an object. If true, raise exception if such a
+        pointer is encountered
         """
 
         self.expr_types = expr_types
         self.types_mngr = types_mngr
+        self.enforce_strict_access = enforce_strict_access
 
     def updt_expr_types(self, expr_types):
         """Update expr_types
@@ -676,12 +682,13 @@ class CTypeAnalyzer(ExprReducer):
             obj = self.get_typeof(
                 base_type.objtype, sub_offset, deref, lvl + 1)
             new_type = obj
+
         elif isinstance(base_type, ObjCDecl):
-            if offset != 0:
+            if self.enforce_strict_access and offset != 0:
                 return []
             obj = ObjCPtr(base_type, void_type.align, void_type.size)
-
             new_type = [obj]
+
         elif isinstance(base_type, ObjCUnion):
             out = []
             if offset == 0 and not deref:
@@ -697,6 +704,8 @@ class CTypeAnalyzer(ExprReducer):
                 out += new_type
             new_type = out
         elif isinstance(base_type, ObjCPtr):
+            if self.enforce_strict_access:
+                assert offset % base_type.size == 0
             obj = ObjCPtr(base_type, void_type.align, void_type.size)
             new_type = [obj]
         else:
@@ -781,7 +790,8 @@ class CTypeAnalyzer(ExprReducer):
                 r_target = ptr_target.objtype
                 # ptr_target: ptr<elem>
                 # r_target: elem
-                if r_target.size != node.expr.size / 8:
+                if (not(self.enforce_strict_access) or
+                    r_target.size != node.expr.size / 8):
                     continue
                 found.append(r_target)
         if not found:
@@ -960,21 +970,15 @@ class ExprToAccessC(ExprReducer):
                     finalobj = sname
                     out.append(finalobj)
             new_type = out
+
         elif isinstance(base_type, ObjCPtr):
             elem_num = offset / base_type.size
+            if self.enforce_strict_access:
+                assert offset % base_type.size == 0
 
-            if elem_num == 0:
-                if self.enforce_strict_access:
-                    assert offset % base_type.size == 0
-                nobj = CGenArray(cgenobj, elem_num,
-                                 void_type.align, void_type.size)
-                new_type = [(nobj)]
-            else:
-                if self.enforce_strict_access:
-                    assert offset % base_type.size == 0
-                nobj = CGenArray(cgenobj, elem_num,
-                                 void_type.align, void_type.size)
-                new_type = [(nobj)]
+            nobj = CGenArray(cgenobj, elem_num,
+                             void_type.align, void_type.size)
+            new_type = [(nobj)]
 
         else:
             raise NotImplementedError("deref type %r" % base_type)
@@ -1348,6 +1352,11 @@ class CTypesManager(object):
         """Retrieve a void* objc"""
         return self.leaf_types.types.get(CTypePtr(CTypeId('void')))
 
+    @property
+    def padding(self):
+        """Retrieve a padding ctype"""
+        return CTypeId(PADDING_TYPE_NAME)
+
     def _get_objc(self, type_id, resolved=None, to_fix=None, lvl=0):
         if resolved is None:
             resolved = {}
@@ -1378,11 +1387,19 @@ class CTypesManager(object):
             align_max, size_max = 0, 0
 
             offset, align_max = 0, 1
+            pad_index = 0
             for name, field in type_id.fields:
                 objc = self._get_objc(field, resolved, to_fix, lvl + 1)
                 resolved[field] = objc
                 align_max = max(align_max, objc.align)
-                offset = self.struct_compute_field_offset(objc, offset)
+                new_offset = self.struct_compute_field_offset(objc, offset)
+                if new_offset - offset:
+                    pad_name = "__PAD__%d__" % pad_index
+                    pad_index += 1
+                    size = new_offset - offset
+                    pad_objc = self._get_objc(CTypeArray(self.padding, size), resolved, to_fix, lvl + 1)
+                    out.add_field(pad_name, pad_objc, offset, pad_objc.size)
+                offset = new_offset
                 out.add_field(name, objc, offset, objc.size)
                 offset += objc.size
 
@@ -1573,7 +1590,8 @@ class CHandler(object):
                  simplify_c=access_simplifier,
                  enforce_strict_access=True):
         self.exprc2expr = self.exprCToExpr_cls(expr_types, types_mngr)
-        self.type_analyzer = self.cTypeAnalyzer_cls(expr_types, types_mngr)
+        self.type_analyzer = self.cTypeAnalyzer_cls(expr_types, types_mngr,
+                                                   enforce_strict_access)
         self.access_c_gen = self.exprToAccessC_cls(expr_types,
                                                    types_mngr,
                                                    enforce_strict_access)
diff --git a/miasm2/expression/simplifications_common.py b/miasm2/expression/simplifications_common.py
index 01db7597..eb9d0958 100644
--- a/miasm2/expression/simplifications_common.py
+++ b/miasm2/expression/simplifications_common.py
@@ -542,6 +542,17 @@ def simp_compose(e_s, e):
             new_e = args[0].arg >> ExprInt(args[0].start, args[0].arg.size)
             return new_e
 
+    # {@X[base + i] 0 X, @Y[base + i + X] X (X + Y)} => @(X+Y)[base + i]
+    for i, arg in enumerate(args[:-1]):
+        nxt = args[i + 1]
+        if arg.is_mem() and nxt.is_mem():
+            gap = e_s(nxt.arg - arg.arg)
+            if gap.is_int() and int(gap) == arg.size / 8:
+                args = args[:i] + [ExprMem(arg.arg,
+                                          arg.size + nxt.size)] + args[i + 2:]
+                return ExprCompose(*args)
+
+
     # Compose with ExprCond with integers for src1/src2 and intergers =>
     # propagage integers
     # {XXX?(0x0,0x1)?(0x0,0x1),0,8, 0x0,8,32} => XXX?(int1, int2)
diff --git a/miasm2/jitter/vm_mngr_py.c b/miasm2/jitter/vm_mngr_py.c
index 5f25b707..35633b7f 100644
--- a/miasm2/jitter/vm_mngr_py.c
+++ b/miasm2/jitter/vm_mngr_py.c
@@ -235,7 +235,7 @@ PyObject* vm_get_mem(VmMngr* self, PyObject* args)
 
        ret = vm_read_mem(&self->vm_mngr, addr, &buf_out, size);
        if (ret < 0) {
-	       RAISE(PyExc_TypeError,"Cannot find address");
+	       RAISE(PyExc_RuntimeError,"Cannot find address");
        }
 
        obj_out = PyString_FromStringAndSize(buf_out, size);
diff --git a/test/arch/x86/unit/mn_pushpop.py b/test/arch/x86/unit/mn_pushpop.py
index ffcc3fa5..7ac400c0 100755
--- a/test/arch/x86/unit/mn_pushpop.py
+++ b/test/arch/x86/unit/mn_pushpop.py
@@ -39,6 +39,7 @@ class Test_PUSHAD_32(Asm_Test_32):
     '''
 
     def check(self):
+        assert self.myjit.cpu.ESP == self.stk_origin - 0x4 * 8
         buf = self.myjit.vm.get_mem(self.myjit.cpu.ESP, 0x4 * 8)
         assert(buf == self.buf)
 
@@ -65,6 +66,7 @@ class Test_PUSHA_32(Asm_Test_32):
     '''
 
     def check(self):
+        assert self.myjit.cpu.ESP == self.stk_origin - 0x2 * 8
         buf = self.myjit.vm.get_mem(self.myjit.cpu.ESP, 0x2 * 8)
         assert(buf == self.buf)
 
@@ -91,6 +93,7 @@ class Test_PUSHA_16(Asm_Test_16):
     '''
 
     def check(self):
+        assert self.myjit.cpu.ESP == self.stk_origin - 0x2 * 8
         buf = self.myjit.vm.get_mem(self.myjit.cpu.SP, 0x2 * 8)
         assert(buf == self.buf)
 
@@ -117,12 +120,202 @@ class Test_PUSHAD_16(Asm_Test_16):
     '''
 
     def check(self):
+        assert self.myjit.cpu.ESP == self.stk_origin - 0x4 * 8
         buf = self.myjit.vm.get_mem(self.myjit.cpu.SP, 0x4 * 8)
         assert(buf == self.buf)
 
 
+class Test_PUSH_mode32_32(Asm_Test_32):
+    MYSTRING = "test push mode32 32"
+
+    def prepare(self):
+        self.myjit.ir_arch.symbol_pool.add_label("lbl_ret", self.ret_addr)
+
+    def test_init(self):
+        init_regs(self)
+        self.buf = ""
+        self.buf += pck32(0x11223344)
+
+    TXT = '''
+    main:
+       PUSH 0x11223344
+       JMP lbl_ret
+    '''
+
+    def check(self):
+        assert self.myjit.cpu.ESP == self.stk_origin - 0x4
+        buf = self.myjit.vm.get_mem(self.myjit.cpu.ESP, 0x4)
+        assert(buf == self.buf)
+
+
+class Test_PUSH_mode32_16(Asm_Test_32):
+    MYSTRING = "test push mode32 16"
+
+    def prepare(self):
+        self.myjit.ir_arch.symbol_pool.add_label("lbl_ret", self.ret_addr)
+
+    def test_init(self):
+        init_regs(self)
+        self.buf = ""
+        self.buf += pck16(0x1122)
+
+    TXT = '''
+    main:
+       PUSHW 0x1122
+       JMP lbl_ret
+    '''
+
+    def check(self):
+        assert self.myjit.cpu.ESP == self.stk_origin - 0x2
+        buf = self.myjit.vm.get_mem(self.myjit.cpu.ESP, 0x2)
+        assert(buf == self.buf)
+
+
+class Test_PUSH_mode16_16(Asm_Test_16):
+    MYSTRING = "test push mode16 16"
+
+    def prepare(self):
+        self.myjit.ir_arch.symbol_pool.add_label("lbl_ret", self.ret_addr)
+
+    def test_init(self):
+        init_regs(self)
+        self.buf = ""
+        self.buf += pck16(0x1122)
+
+    TXT = '''
+    main:
+       PUSHW 0x1122
+       JMP lbl_ret
+    '''
+
+    def check(self):
+        assert self.myjit.cpu.ESP == self.stk_origin - 0x2
+        buf = self.myjit.vm.get_mem(self.myjit.cpu.ESP, 0x2)
+        assert(buf == self.buf)
+
+
+class Test_PUSH_mode16_32(Asm_Test_16):
+    MYSTRING = "test push mode16 32"
+
+    def prepare(self):
+        self.myjit.ir_arch.symbol_pool.add_label("lbl_ret", self.ret_addr)
+
+    def test_init(self):
+        init_regs(self)
+        self.buf = ""
+        self.buf += pck32(0x11223344)
+
+    TXT = '''
+    main:
+       .byte 0x66, 0x68, 0x44, 0x33, 0x22, 0x11
+       JMP lbl_ret
+    '''
+
+    def check(self):
+        assert self.myjit.cpu.ESP == self.stk_origin - 0x4
+        buf = self.myjit.vm.get_mem(self.myjit.cpu.ESP, 0x4)
+        assert(buf == self.buf)
+
+
+class Test_POP_mode32_32(Asm_Test_32):
+    MYSTRING = "test pop mode32 32"
+
+    def prepare(self):
+        self.myjit.ir_arch.symbol_pool.add_label("lbl_ret", self.ret_addr)
+
+    def test_init(self):
+        self.value = 0x11223344
+        self.myjit.push_uint32_t(self.value)
+        init_regs(self)
+
+    TXT = '''
+    main:
+       POP EAX
+       JMP lbl_ret
+    '''
+
+    def check(self):
+        assert self.myjit.cpu.ESP == self.stk_origin + 0x4
+        assert self.myjit.cpu.EAX == self.value
+
+
+class Test_POP_mode32_16(Asm_Test_32):
+    MYSTRING = "test pop mode32 16"
+
+    def prepare(self):
+        self.myjit.ir_arch.symbol_pool.add_label("lbl_ret", self.ret_addr)
+
+    def test_init(self):
+        self.value = 0x1122
+        self.myjit.push_uint16_t(self.value)
+        init_regs(self)
+
+    TXT = '''
+    main:
+       POPW AX
+       JMP lbl_ret
+    '''
+
+    def check(self):
+        assert self.myjit.cpu.ESP == self.stk_origin + 0x2
+        assert self.myjit.cpu.AX == self.value
+
+
+class Test_POP_mode16_16(Asm_Test_16):
+    MYSTRING = "test pop mode16 16"
+
+    def prepare(self):
+        self.myjit.ir_arch.symbol_pool.add_label("lbl_ret", self.ret_addr)
+
+    def test_init(self):
+        self.value = 0x1122
+        self.myjit.push_uint16_t(self.value)
+        init_regs(self)
+
+    TXT = '''
+    main:
+       POPW AX
+       JMP lbl_ret
+    '''
+
+    def check(self):
+        assert self.myjit.cpu.ESP == self.stk_origin + 0x2
+        assert self.myjit.cpu.AX == self.value
+
+
+class Test_POP_mode16_32(Asm_Test_16):
+    MYSTRING = "test pop mode16 32"
+
+    def prepare(self):
+        self.myjit.ir_arch.symbol_pool.add_label("lbl_ret", self.ret_addr)
+
+    def test_init(self):
+        self.value = 0x11223344
+        self.myjit.cpu.SP -= 0x4
+        self.myjit.vm.set_mem(self.myjit.cpu.SP, pck32(self.value))
+        init_regs(self)
+
+    TXT = '''
+    main:
+       POP EAX
+       JMP lbl_ret
+    '''
+
+    def check(self):
+        assert self.myjit.cpu.ESP == self.stk_origin + 0x4
+        assert self.myjit.cpu.EAX == self.value
+
+
 if __name__ == "__main__":
     [test(*sys.argv[1:])() for test in [Test_PUSHA_16, Test_PUSHA_32,
-                                        Test_PUSHAD_16, Test_PUSHAD_32
+                                        Test_PUSHAD_16, Test_PUSHAD_32,
+                                        Test_PUSH_mode32_32,
+                                        Test_PUSH_mode32_16,
+                                        Test_PUSH_mode16_16,
+                                        Test_PUSH_mode16_32,
+                                        Test_POP_mode32_32,
+                                        Test_POP_mode32_16,
+                                        Test_POP_mode16_16,
+                                        Test_POP_mode16_32,
                                         ]
     ]
diff --git a/test/expression/simplifications.py b/test/expression/simplifications.py
index 60c328dc..efabddb5 100644
--- a/test/expression/simplifications.py
+++ b/test/expression/simplifications.py
@@ -314,6 +314,11 @@ to_test = [(ExprInt(1, 32) - ExprInt(1, 32), ExprInt(0, 32)),
     (ExprOp("imod", ExprInt(0x0123, 16), ExprInt(0xfffb, 16))[:8],
      ExprInt(0x01, 8)),
 
+    (ExprCompose(ExprInt(0x0123, 16), ExprMem(a + ExprInt(0x40, a.size), 16),
+                 ExprMem(a + ExprInt(0x42, a.size), 16), ExprInt(0x0321, 16)),
+     ExprCompose(ExprInt(0x0123, 16), ExprMem(a + ExprInt(0x40, a.size), 32),
+                 ExprInt(0x0321, 16))),
+
 ]
 
 for e, e_check in to_test[:]: