diff options
Diffstat (limited to 'miasm2/ir/translators/C.py')
| -rw-r--r-- | miasm2/ir/translators/C.py | 372 |
1 files changed, 271 insertions, 101 deletions
diff --git a/miasm2/ir/translators/C.py b/miasm2/ir/translators/C.py index f8fd4d3b..066c0f32 100644 --- a/miasm2/ir/translators/C.py +++ b/miasm2/ir/translators/C.py @@ -3,6 +3,22 @@ from miasm2.core import asmblock from miasm2.expression.modint import size2mask +def int_size_to_bn(value, size): + if size < 32: + size = 32 + int_str = "%.8x" % value + size_nibble = 8 + else: + # size must be multiple of 4 + size = ((size + 31) / 32) * 32 + size_nibble = size / 4 + fmt_str = "%%.%dx" % size_nibble + int_str = fmt_str % value + assert len(int_str) == size_nibble + return int_str, size_nibble + + + class TranslatorC(Translator): "Translate a Miasm expression to an equivalent C code" @@ -18,6 +34,8 @@ class TranslatorC(Translator): '>>>': 'rot_right', } + NATIVE_INT_MAX_SIZE = 64 + def __init__(self, loc_db=None, **kwargs): """Instance a C translator @loc_db: LocationDB instance @@ -28,38 +46,34 @@ class TranslatorC(Translator): def _size2mask(self, size): """Return a C string corresponding to the size2mask operation, with support for - @size <= 128""" + @size <= 64""" + assert size <= 64 mask = size2mask(size) - if size > 64: - # Avoid "integer constant is too large for its type" error - return "(0x%x | ((uint128_t) 0x%x << 64))" % ( - mask & 0xFFFFFFFFFFFFFFFF, - (mask >> 64) & 0xFFFFFFFFFFFFFFFF, - ) return "0x%x" % mask def from_ExprId(self, expr): return str(expr) def from_ExprInt(self, expr): - if expr.size == 128: - # Avoid "integer constant is too large for its type" error - return "(0x%x | ((uint128_t) 0x%x << 64))" % ( - int(expr) & 0xFFFFFFFFFFFFFFFF, - (int(expr) >> 64) & 0xFFFFFFFFFFFFFFFF, - ) - return "0x%x" % expr.arg.arg + if expr.size <= self.NATIVE_INT_MAX_SIZE: + assert expr.size <= 64 + return "0x%x" % expr.arg.arg + value, int_size = int_size_to_bn(int(expr), expr.size) + return 'bignum_from_string("%s", %d)' % (value, int_size) def from_ExprLoc(self, expr): loc_key = expr.loc_key if self.loc_db is None: return str(loc_key) - offset = self.loc_db.get_location_offset(loc_key) if offset is None: return str(loc_key) - return "0x%x" % offset + if expr.size <= self.NATIVE_INT_MAX_SIZE: + return "0x%x" % offset + + value, int_size = int_size_to_bn(offset, 64) + return 'bignum_from_string("%s", %d)' % (value, int_size) def from_ExprAff(self, expr): new_dst = self.from_expr(expr.dst) @@ -67,33 +81,66 @@ class TranslatorC(Translator): return "%s = %s" % (new_dst, new_src) def from_ExprCond(self, expr): - new_cond = self.from_expr(expr.cond) - new_src1 = self.from_expr(expr.src1) - new_src2 = self.from_expr(expr.src2) - return "(%s?%s:%s)" % (new_cond, new_src1, new_src2) + cond = self.from_expr(expr.cond) + src1 = self.from_expr(expr.src1) + src2 = self.from_expr(expr.src2) + if not expr.cond.size <= self.NATIVE_INT_MAX_SIZE: + cond = "(!bignum_is_zero(%s))" % cond + out = "(%s?%s:%s)" % (cond, src1, src2) + return out def from_ExprMem(self, expr): - new_ptr = self.from_expr(expr.arg) - return "MEM_LOOKUP_%.2d(jitcpu, %s)" % (expr.size, new_ptr) + ptr = expr.arg + if ptr.size <= self.NATIVE_INT_MAX_SIZE: + new_ptr = self.from_expr(ptr) + if expr.size <= self.NATIVE_INT_MAX_SIZE: + # Native ptr, Native Mem + return "MEM_LOOKUP_%.2d(jitcpu, %s)" % (expr.size, new_ptr) + else: + # Native ptr, BN mem + return "MEM_LOOKUP_INT_BN(jitcpu, %d, %s)" % (expr.size, new_ptr) + # BN ptr + new_ptr = self.from_expr(ptr) + + if expr.size <= self.NATIVE_INT_MAX_SIZE: + # BN ptr, Native Mem + return "MEM_LOOKUP_BN_INT(jitcpu, %d, %s)" % (expr.size, new_ptr) + else: + # BN ptr, BN mem + return "MEM_LOOKUP_BN_BN(jitcpu, %d, %s)" % (expr.size, new_ptr) def from_ExprOp(self, expr): if len(expr.args) == 1: if expr.op == 'parity': - return "parity(%s&%s)" % ( - self.from_expr(expr.args[0]), - self._size2mask(expr.args[0].size), - ) + arg = expr.args[0] + out = self.from_expr(arg) + if arg.size <= self.NATIVE_INT_MAX_SIZE: + out = "(%s&%s)" % (out, self._size2mask(arg.size)) + else: + out = 'bignum_mask(%s, 8)' % (out, 8) + out = 'bignum_to_uint64(%s)' % out + out = 'parity(%s)' % out + return out + elif expr.op in ['cntleadzeros', 'cnttrailzeros']: - return "%s(0x%x, %s)" % ( - expr.op, - expr.args[0].size, - self.from_expr(expr.args[0]) - ) + arg = expr.args[0] + out = self.from_expr(arg) + if arg.size <= self.NATIVE_INT_MAX_SIZE: + out = "%s(0x%x, %s)" % (expr.op, expr.args[0].size, out) + else: + out = "bignum_%s(%s, %d)" % (expr.op, out, arg.size) + return out + elif expr.op == '!': - return "(~ %s)&%s" % ( - self.from_expr(expr.args[0]), - self._size2mask(expr.args[0].size), - ) + arg = expr.args[0] + out = self.from_expr(arg) + if expr.size <= self.NATIVE_INT_MAX_SIZE: + out = "(~ %s)&%s" % (out, self._size2mask(arg.size)) + else: + out = "bignum_not(%s)" % out + out = "bignum_mask(%s, expr.size)" % out + return out + elif expr.op in [ "ftan", "frndint", "f2xm1", "fsin", "fsqrt", "fabs", "fcos", "fchs", @@ -105,12 +152,23 @@ class TranslatorC(Translator): ) elif (expr.op.startswith("access_") or expr.op.startswith("load_") or - expr.op.startswith("fxam_c") or - expr.op in ["-"]): - return "%s(%s)" % ( - expr.op, - self.from_expr(expr.args[0]) - ) + expr.op.startswith("fxam_c")): + arg = expr.args[0] + out = self.from_expr(arg) + out = "%s(%s)" % (expr.op, out) + return out + + elif expr.op == "-": + arg = expr.args[0] + out = self.from_expr(arg) + if arg.size <= self.NATIVE_INT_MAX_SIZE: + out = "(%s(%s))" % (expr.op, out) + out = "(%s&%s)" % (out, self._size2mask(arg.size)) + else: + out = "bignum_sub(bignum_from_uint64(0), %s)" % out + out = "bignum_mask(%s, %d)"% (out, expr.size) + return out + elif expr.op.startswith("fpround_"): return "%s_fp%d(%s)" % ( expr.op, @@ -170,20 +228,52 @@ class TranslatorC(Translator): self._size2mask(expr.args[1].size), ) elif expr.op in self.dct_shift: - return 'SHIFT_%s(%d, %s, %s)' % ( - self.dct_shift[expr.op].upper(), - expr.args[0].size, - self.from_expr(expr.args[0]), - self.from_expr(expr.args[1]) - ) - elif expr.is_associative() or expr.op in ["%", "/"]: - oper = ['(%s&%s)' % ( - self.from_expr(arg), - self._size2mask(arg.size) - ) + arg0 = self.from_expr(expr.args[0]) + arg1 = self.from_expr(expr.args[1]) + if expr.size <= self.NATIVE_INT_MAX_SIZE: + out = 'SHIFT_%s(%d, %s, %s)' % ( + self.dct_shift[expr.op].upper(), + expr.args[0].size, + self.from_expr(expr.args[0]), + self.from_expr(expr.args[1]) + ) + else: + op = { + "<<": "lshift", + ">>": "rshift", + "a>>": "a_rshift" + } + out = "bignum_%s(%s, bignum_to_uint64(%s))" % ( + op[expr.op], arg0, arg1 + ) + out = "bignum_mask(%s, %d)"% (out, expr.size) + return out + + elif expr.is_associative(): + args = [self.from_expr(arg) for arg in expr.args] - oper = str(expr.op).join(oper) - return "((%s)&%s)" % (oper, self._size2mask(expr.args[0].size)) + if expr.size <= self.NATIVE_INT_MAX_SIZE: + out = (" %s " % expr.op).join(args) + out = "((%s)&%s)" % (out, self._size2mask(expr.size)) + else: + op_to_bn_func = { + "+": "add", + "*": "mul", + "|": "or", + "^": "xor", + "&": "and", + } + args = list(expr.args) + out = self.from_expr(args.pop()) + while args: + out = 'bignum_mask(bignum_%s(%s, %s), %d)' % ( + op_to_bn_func[expr.op], + out, + self.from_expr(args.pop()), + expr.size + ) + return out + elif expr.op in ['-']: return '(((%s&%s) %s (%s&%s))&%s)' % ( self.from_expr(expr.args[0]), @@ -194,13 +284,27 @@ class TranslatorC(Translator): self._size2mask(expr.args[0].size) ) elif expr.op in self.dct_rot: - return '(%s(%s, %s, %s) &%s)' % ( - self.dct_rot[expr.op], - expr.args[0].size, - self.from_expr(expr.args[0]), - self.from_expr(expr.args[1]), - self._size2mask(expr.args[0].size), - ) + arg0 = self.from_expr(expr.args[0]) + arg1 = self.from_expr(expr.args[1]) + if expr.size <= self.NATIVE_INT_MAX_SIZE: + out = '(%s(%s, %s, %s) &%s)' % ( + self.dct_rot[expr.op], + expr.args[0].size, + self.from_expr(expr.args[0]), + self.from_expr(expr.args[1]), + self._size2mask(expr.args[0].size), + ) + else: + op = { + ">>>": "ror", + "<<<": "rol" + } + out = "bignum_%d(%s, %d, bignum_to_uint64(%s))" % ( + op[expr.op], arg0, expr.size, arg1 + ) + out = "bignum_mask(%s, %d)"% (out, expr.size) + return out + elif expr.op == 'x86_cpuid': return "%s(%s, %s)" % (expr.op, self.from_expr(expr.args[0]), @@ -208,24 +312,62 @@ class TranslatorC(Translator): elif (expr.op.startswith("fcom") or expr.op in ["fadd", "fsub", "fdiv", 'fmul', "fscale", "fprem", "fprem_lsb", "fyl2x", "fpatan"]): - return "fpu_%s%d(%s, %s)" % ( - expr.op, - expr.size, - self.from_expr(expr.args[0]), - self.from_expr(expr.args[1]), - ) + arg0 = self.from_expr(expr.args[0]) + arg1 = self.from_expr(expr.args[1]) + if not expr.args[0].size <= self.NATIVE_INT_MAX_SIZE: + raise ValueError("Bad semantic: fpu do operations do not support such size") + out = "fpu_%s%d(%s, %s)" % (expr.op, expr.size, arg0, arg1) + return out + elif expr.op == "segm": return "segm2addr(jitcpu, %s, %s)" % ( self.from_expr(expr.args[0]), self.from_expr(expr.args[1]) ) - elif expr.op in ['udiv', 'umod', 'idiv', 'imod']: - return '%s%d(%s, %s)' % ( - expr.op, - expr.args[0].size, - self.from_expr(expr.args[0]), - self.from_expr(expr.args[1]) - ) + + elif expr.op in ['udiv', 'umod']: + arg0 = self.from_expr(expr.args[0]) + arg1 = self.from_expr(expr.args[1]) + + if expr.size <= self.NATIVE_INT_MAX_SIZE: + out = '%s%d(%s, %s)' % ( + expr.op, + expr.args[0].size, + self.from_expr(expr.args[0]), + self.from_expr(expr.args[1]) + ) + else: + out = "bignum_%s(%s, %s)" % ( + expr.op, + self.from_expr(expr.args[0]), + self.from_expr(expr.args[1]) + ) + out = "bignum_mask(%s, %d)"% (out, expr.size) + return out + + + + elif expr.op in ['idiv', 'imod']: + arg0 = self.from_expr(expr.args[0]) + arg1 = self.from_expr(expr.args[1]) + + if expr.size <= self.NATIVE_INT_MAX_SIZE: + out = '%s%d(%s, %s)' % ( + expr.op, + expr.args[0].size, + self.from_expr(expr.args[0]), + self.from_expr(expr.args[1]) + ) + else: + out = "bignum_%s(%s, %s, %d)" % ( + expr.op, + self.from_expr(expr.args[0]), + self.from_expr(expr.args[1]), + expr.size + ) + out = "bignum_mask(%s, %d)"% (out, expr.size) + return out + elif expr.op in ["bcdadd", "bcdadd_cf"]: return "%s_%d(%s, %s)" % ( expr.op, expr.args[0].size, @@ -250,36 +392,64 @@ class TranslatorC(Translator): raise NotImplementedError('Unknown op: %s' % expr.op) def from_ExprSlice(self, expr): - # XXX check mask for 64 bit & 32 bit compat - return "((%s>>%d) &%s)" % ( - self.from_expr(expr.arg), - expr.start, - self._size2mask(expr.stop - expr.start) - ) + out = self.from_expr(expr.arg) + if expr.arg.size <= self.NATIVE_INT_MAX_SIZE: + # XXX check mask for 64 bit & 32 bit compat + out = "((%s>>%d) &%s)" % ( + out, expr.start, + self._size2mask(expr.stop - expr.start) + ) + else: + out = "bignum_rshift(%s, %d)" % (out, expr.start) + out = "bignum_mask(%s, %d)" % (out, expr.stop - expr.start) + + if expr.size <= self.NATIVE_INT_MAX_SIZE: + # Convert bignum to int + out = "bignum_to_uint64(%s)" % out + return out def from_ExprCompose(self, expr): - out = [] - # XXX check mask for 64 bit & 32 bit compat - if expr.size in [8, 16, 32, 64, 128]: - size = expr.size + if expr.size <= self.NATIVE_INT_MAX_SIZE: + + out = [] + # XXX check mask for 64 bit & 32 bit compat + if expr.size in [8, 16, 32, 64, 128]: + size = expr.size + else: + # Uncommon expression size, use at least uint8 + size = max(expr.size, 8) + next_power = 1 + while next_power <= size: + next_power <<= 1 + size = next_power + + dst_cast = "uint%d_t" % size + for index, arg in expr.iter_args(): + out.append("(((%s)(%s & %s)) << %d)" % ( + dst_cast, + self.from_expr(arg), + self._size2mask(arg.size), + index) + ) + out = ' | '.join(out) + return '(' + out + ')' else: - # Uncommon expression size, use at least uint8 - size = max(expr.size, 8) - next_power = 1 - while next_power <= size: - next_power <<= 1 - size = next_power - - dst_cast = "uint%d_t" % size - for index, arg in expr.iter_args(): - out.append("(((%s)(%s & %s)) << %d)" % ( - dst_cast, - self.from_expr(arg), - self._size2mask(arg.size), - index) - ) - out = ' | '.join(out) - return '(' + out + ')' + # Convert all parts to bignum + args = [] + for index, arg in expr.iter_args(): + arg_str = self.from_expr(arg) + if arg.size <= self.NATIVE_INT_MAX_SIZE: + arg_str = '((%s) & %s)' % (arg_str, self._size2mask(arg.size)) + arg_str = 'bignum_from_uint64(%s)' % arg_str + else: + arg_str = 'bignum_mask(%s, %d)' % (arg_str, arg.size) + arg_str = 'bignum_lshift(%s, %d)' % (arg_str, index) + args.append(arg_str) + out = args.pop() + while args: + arg = args.pop() + out = "bignum_or(%s, %s)" % (out, arg) + return out # Register the class |