Miasm2
 All Classes Namespaces Files Functions Variables Typedefs Properties Macros
simplifications_common.py
Go to the documentation of this file.
1 # ----------------------------- #
2 # Common simplifications passes #
3 # ----------------------------- #
4 
5 
8 
9 
11  """This passe includes:
12  - Constant folding
13  - Common logical identities
14  - Common binary identities
15  """
16 
17  # merge associatif op
18  args = list(e.args)
19  op = e.op
20  # simpl integer manip
21  # int OP int => int
22  # TODO: <<< >>> << >> are architecture dependant
23  if op in op_propag_cst:
24  while (len(args) >= 2 and
25  isinstance(args[-1], ExprInt) and
26  isinstance(args[-2], ExprInt)):
27  i2 = args.pop()
28  i1 = args.pop()
29  if op == '+':
30  o = i1.arg + i2.arg
31  elif op == '*':
32  o = i1.arg * i2.arg
33  elif op == '^':
34  o = i1.arg ^ i2.arg
35  elif op == '&':
36  o = i1.arg & i2.arg
37  elif op == '|':
38  o = i1.arg | i2.arg
39  elif op == '>>':
40  o = i1.arg >> i2.arg
41  elif op == '<<':
42  o = i1.arg << i2.arg
43  elif op == 'a>>':
44  x1 = mod_size2int[i1.arg.size](i1.arg)
45  x2 = mod_size2int[i2.arg.size](i2.arg)
46  o = mod_size2uint[i1.arg.size](x1 >> x2)
47  elif op == '>>>':
48  rounds = i2.arg
49  o = i1.arg >> i2.arg | i1.arg << (i1.size - i2.arg)
50  elif op == '<<<':
51  o = i1.arg << i2.arg | i1.arg >> (i1.size - i2.arg)
52  elif op == '/':
53  o = i1.arg / i2.arg
54  elif op == '%':
55  o = i1.arg % i2.arg
56  elif op == 'idiv':
57  assert(i2.arg.arg)
58  x1 = mod_size2int[i1.arg.size](i1.arg)
59  x2 = mod_size2int[i2.arg.size](i2.arg)
60  o = mod_size2uint[i1.arg.size](x1 / x2)
61  elif op == 'imod':
62  assert(i2.arg.arg)
63  x1 = mod_size2int[i1.arg.size](i1.arg)
64  x2 = mod_size2int[i2.arg.size](i2.arg)
65  o = mod_size2uint[i1.arg.size](x1 % x2)
66  elif op == 'umod':
67  assert(i2.arg.arg)
68  x1 = mod_size2uint[i1.arg.size](i1.arg)
69  x2 = mod_size2uint[i2.arg.size](i2.arg)
70  o = mod_size2uint[i1.arg.size](x1 % x2)
71  elif op == 'udiv':
72  assert(i2.arg.arg)
73  x1 = mod_size2uint[i1.arg.size](i1.arg)
74  x2 = mod_size2uint[i2.arg.size](i2.arg)
75  o = mod_size2uint[i1.arg.size](x1 / x2)
76 
77 
78 
79  o = ExprInt(o, i1.size)
80  args.append(o)
81 
82  # bsf(int) => int
83  if op == "bsf" and isinstance(args[0], ExprInt) and args[0].arg != 0:
84  i = 0
85  while args[0].arg & (1 << i) == 0:
86  i += 1
87  return ExprInt_from(args[0], i)
88 
89  # bsr(int) => int
90  if op == "bsr" and isinstance(args[0], ExprInt) and args[0].arg != 0:
91  i = args[0].size - 1
92  while args[0].arg & (1 << i) == 0:
93  i -= 1
94  return ExprInt_from(args[0], i)
95 
96  # -(-(A)) => A
97  if op == '-' and len(args) == 1 and isinstance(args[0], ExprOp) and \
98  args[0].op == '-' and len(args[0].args) == 1:
99  return args[0].args[0]
100 
101  # -(int) => -int
102  if op == '-' and len(args) == 1 and isinstance(args[0], ExprInt):
103  return ExprInt(-args[0].arg)
104  # A op 0 =>A
105  if op in ['+', '|', "^", "<<", ">>", "<<<", ">>>"] and len(args) > 1:
106  if isinstance(args[-1], ExprInt) and args[-1].arg == 0:
107  args.pop()
108  # A - 0 =>A
109  if op == '-' and len(args) > 1 and args[-1].arg == 0:
110  assert(len(args) == 2) # Op '-' with more than 2 args: SantityCheckError
111  return args[0]
112 
113  # A * 1 =>A
114  if op == "*" and len(args) > 1:
115  if isinstance(args[-1], ExprInt) and args[-1].arg == 1:
116  args.pop()
117 
118  # for cannon form
119  # A * -1 => - A
120  if op == "*" and len(args) > 1:
121  if (isinstance(args[-1], ExprInt) and
122  args[-1].arg == (1 << args[-1].size) - 1):
123  args.pop()
124  args[-1] = - args[-1]
125 
126  # op A => A
127  if op in ['+', '*', '^', '&', '|', '>>', '<<',
128  'a>>', '<<<', '>>>', 'idiv', 'imod', 'umod', 'udiv'] and len(args) == 1:
129  return args[0]
130 
131  # A-B => A + (-B)
132  if op == '-' and len(args) > 1:
133  if len(args) > 2:
134  raise ValueError(
135  'sanity check fail on expr -: should have one or 2 args ' +
136  '%r %s' % (e, e))
137  return ExprOp('+', args[0], -args[1])
138 
139  # A op 0 => 0
140  if op in ['&', "*"] and isinstance(args[1], ExprInt) and args[1].arg == 0:
141  return ExprInt_from(e, 0)
142 
143  # - (A + B +...) => -A + -B + -C
144  if (op == '-' and
145  len(args) == 1 and
146  isinstance(args[0], ExprOp) and
147  args[0].op == '+'):
148  args = [-a for a in args[0].args]
149  e = ExprOp('+', *args)
150  return e
151 
152  # -(a?int1:int2) => (a?-int1:-int2)
153  if (op == '-' and
154  len(args) == 1 and
155  isinstance(args[0], ExprCond) and
156  isinstance(args[0].src1, ExprInt) and
157  isinstance(args[0].src2, ExprInt)):
158  i1 = args[0].src1
159  i2 = args[0].src2
160  i1 = ExprInt_from(i1, -i1.arg)
161  i2 = ExprInt_from(i2, -i2.arg)
162  return ExprCond(args[0].cond, i1, i2)
163 
164  i = 0
165  while i < len(args) - 1:
166  j = i + 1
167  while j < len(args):
168  # A ^ A => 0
169  if op == '^' and args[i] == args[j]:
170  args[i] = ExprInt_from(args[i], 0)
171  del(args[j])
172  continue
173  # A + (- A) => 0
174  if op == '+' and isinstance(args[j], ExprOp) and args[j].op == "-":
175  if len(args[j].args) == 1 and args[i] == args[j].args[0]:
176  args[i] = ExprInt_from(args[i], 0)
177  del(args[j])
178  continue
179  # (- A) + A => 0
180  if op == '+' and isinstance(args[i], ExprOp) and args[i].op == "-":
181  if len(args[i].args) == 1 and args[j] == args[i].args[0]:
182  args[i] = ExprInt_from(args[i], 0)
183  del(args[j])
184  continue
185  # A | A => A
186  if op == '|' and args[i] == args[j]:
187  del(args[j])
188  continue
189  # A & A => A
190  if op == '&' and args[i] == args[j]:
191  del(args[j])
192  continue
193  j += 1
194  i += 1
195 
196  if op in ['|', '&', '%', '/'] and len(args) == 1:
197  return args[0]
198 
199  # A <<< A.size => A
200  if (op in ['<<<', '>>>'] and
201  isinstance(args[1], ExprInt) and
202  args[1].arg == args[0].size):
203  return args[0]
204 
205  # A <<< X <<< Y => A <<< (X+Y) (ou <<< >>>)
206  if (op in ['<<<', '>>>'] and
207  isinstance(args[0], ExprOp) and
208  args[0].op in ['<<<', '>>>']):
209  op1 = op
210  op2 = args[0].op
211  if op1 == op2:
212  op = op1
213  args1 = args[0].args[1] + args[1]
214  else:
215  op = op2
216  args1 = args[0].args[1] - args[1]
217 
218  args0 = args[0].args[0]
219  args = [args0, args1]
220 
221  # A >> X >> Y => A >> (X+Y)
222  if (op in ['<<', '>>'] and
223  isinstance(args[0], ExprOp) and
224  args[0].op == op):
225  args = [args[0].args[0], args[0].args[1] + args[1]]
226 
227  # ((A & A.mask)
228  if op == "&" and args[-1] == e.mask:
229  return ExprOp('&', *args[:-1])
230 
231  # ((A | A.mask)
232  if op == "|" and args[-1] == e.mask:
233  return args[-1]
234 
235  # ! (!X + int) => X - int
236  # TODO
237 
238  # ((A & mask) >> shift) whith mask < 2**shift => 0
239  if (op == ">>" and
240  isinstance(args[1], ExprInt) and
241  isinstance(args[0], ExprOp) and args[0].op == "&"):
242  if (isinstance(args[0].args[1], ExprInt) and
243  2 ** args[1].arg > args[0].args[1].arg):
244  return ExprInt_from(args[0], 0)
245 
246  # parity(int) => int
247  if op == 'parity' and isinstance(args[0], ExprInt):
248  return ExprInt1(parity(args[0].arg))
249 
250  # (-a) * b * (-c) * (-d) => (-a) * b * c * d
251  if op == "*" and len(args) > 1:
252  new_args = []
253  counter = 0
254  for a in args:
255  if isinstance(a, ExprOp) and a.op == '-' and len(a.args) == 1:
256  new_args.append(a.args[0])
257  counter += 1
258  else:
259  new_args.append(a)
260  if counter % 2:
261  return -ExprOp(op, *new_args)
262  args = new_args
263 
264  # A << int with A ExprCompose => move index
265  if op == "<<" and isinstance(args[0], ExprCompose) and isinstance(args[1], ExprInt):
266  final_size = args[0].size
267  shift = int(args[1].arg)
268  new_args = []
269  # shift indexes
270  for expr, start, stop in args[0].args:
271  new_args.append((expr, start+shift, stop+shift))
272  # filter out expression
273  filter_args = []
274  min_index = final_size
275  for expr, start, stop in new_args:
276  if start >= final_size:
277  continue
278  if stop > final_size:
279  expr = expr[:expr.size - (stop - final_size)]
280  stop = final_size
281  filter_args.append((expr, start, stop))
282  min_index = min(start, min_index)
283  # create entry 0
284  expr = ExprInt(0, min_index)
285  filter_args = [(expr, 0, min_index)] + filter_args
286  return ExprCompose(filter_args)
287 
288  # A >> int with A ExprCompose => move index
289  if op == ">>" and isinstance(args[0], ExprCompose) and isinstance(args[1], ExprInt):
290  final_size = args[0].size
291  shift = int(args[1].arg)
292  new_args = []
293  # shift indexes
294  for expr, start, stop in args[0].args:
295  new_args.append((expr, start-shift, stop-shift))
296  # filter out expression
297  filter_args = []
298  max_index = 0
299  for expr, start, stop in new_args:
300  if stop <= 0:
301  continue
302  if start < 0:
303  expr = expr[-start:]
304  start = 0
305  filter_args.append((expr, start, stop))
306  max_index = max(stop, max_index)
307  # create entry 0
308  expr = ExprInt(0, final_size - max_index)
309  filter_args += [(expr, max_index, final_size)]
310  return ExprCompose(filter_args)
311 
312 
313  # Compose(a) OP Compose(b) with a/b same bounds => Compose(a OP b)
314  if op in ['|', '&', '^'] and all([isinstance(arg, ExprCompose) for arg in args]):
315  bounds = set()
316  for arg in args:
317  bound = tuple([(start, stop) for (expr, start, stop) in arg.args])
318  bounds.add(bound)
319  if len(bounds) == 1:
320  bound = list(bounds)[0]
321  new_args = [[expr] for (expr, start, stop) in args[0].args]
322  for sub_arg in args[1:]:
323  for i, (expr, start, stop) in enumerate(sub_arg.args):
324  new_args[i].append(expr)
325  for i, arg in enumerate(new_args):
326  new_args[i] = ExprOp(op, *arg), bound[i][0], bound[i][1]
327  return ExprCompose(new_args)
328 
329  return ExprOp(op, *args)
330 
331 
332 def simp_cond_op_int(e_s, e):
333  "Extract conditions from operations"
334 
335  if not e.op in ["+", "|", "^", "&", "*", '<<', '>>', 'a>>']:
336  return e
337  if len(e.args) < 2:
338  return e
339  if not isinstance(e.args[-1], ExprInt):
340  return e
341  a_int = e.args[-1]
342  conds = []
343  for a in e.args[:-1]:
344  if not isinstance(a, ExprCond):
345  return e
346  conds.append(a)
347  if not conds:
348  return e
349  c = conds.pop()
350  c = ExprCond(c.cond,
351  ExprOp(e.op, c.src1, a_int),
352  ExprOp(e.op, c.src2, a_int))
353  conds.append(c)
354  new_e = ExprOp(e.op, *conds)
355  return new_e
356 
357 
358 def simp_cond_factor(e_s, e):
359  "Merge similar conditions"
360  if not e.op in ["+", "|", "^", "&", "*", '<<', '>>', 'a>>']:
361  return e
362  if len(e.args) < 2:
363  return e
364  conds = {}
365  not_conds = []
366  multi_cond = False
367  for a in e.args:
368  if not isinstance(a, ExprCond):
369  not_conds.append(a)
370  continue
371  c = a.cond
372  if not c in conds:
373  conds[c] = []
374  else:
375  multi_cond = True
376  conds[c].append(a)
377  if not multi_cond:
378  return e
379  c_out = not_conds[:]
380  for c, vals in conds.items():
381  new_src1 = [x.src1 for x in vals]
382  new_src2 = [x.src2 for x in vals]
383  src1 = e_s.expr_simp_wrapper(ExprOp(e.op, *new_src1))
384  src2 = e_s.expr_simp_wrapper(ExprOp(e.op, *new_src2))
385  c_out.append(ExprCond(c, src1, src2))
386 
387  if len(c_out) == 1:
388  new_e = c_out[0]
389  else:
390  new_e = ExprOp(e.op, *c_out)
391  return new_e
392 
393 
394 def simp_slice(e_s, e):
395  "Slice optimization"
396 
397  # slice(A, 0, a.size) => A
398  if e.start == 0 and e.stop == e.arg.size:
399  return e.arg
400  # Slice(int) => int
401  elif isinstance(e.arg, ExprInt):
402  total_bit = e.stop - e.start
403  mask = (1 << (e.stop - e.start)) - 1
404  return ExprInt(int((e.arg.arg >> e.start) & mask), total_bit)
405  # Slice(Slice(A, x), y) => Slice(A, z)
406  elif isinstance(e.arg, ExprSlice):
407  if e.stop - e.start > e.arg.stop - e.arg.start:
408  raise ValueError('slice in slice: getting more val', str(e))
409 
410  new_e = ExprSlice(e.arg.arg, e.start + e.arg.start,
411  e.start + e.arg.start + (e.stop - e.start))
412  return new_e
413  elif isinstance(e.arg, ExprCompose):
414  # Slice(Compose(A), x) => Slice(A, y)
415  for a in e.arg.args:
416  if a[1] <= e.start and a[2] >= e.stop:
417  new_e = a[0][e.start - a[1]:e.stop - a[1]]
418  return new_e
419  # Slice(Compose(A, B, C), x) => Compose(A, B, C) with truncated A/B/C
420  out = []
421  for arg, s_start, s_stop in e.arg.args:
422  # arg is before slice start
423  if e.start >= s_stop:
424  continue
425  # arg is after slice stop
426  elif e.stop <= s_start:
427  continue
428  # arg is fully included in slice
429  elif e.start <= s_start and s_stop <= e.stop:
430  out.append((arg, s_start - e.start, s_stop - e.start))
431  continue
432  # arg is truncated at start
433  if e.start > s_start:
434  slice_start = e.start - s_start
435  a_start = 0
436  else:
437  # arg is not truncated at start
438  slice_start = 0
439  a_start = s_start - e.start
440  # a is truncated at stop
441  if e.stop < s_stop:
442  slice_stop = arg.size + e.stop - s_stop - slice_start
443  a_stop = e.stop - e.start
444  else:
445  slice_stop = arg.size
446  a_stop = s_stop - e.start
447  out.append((arg[slice_start:slice_stop], a_start, a_stop))
448  return ExprCompose(out)
449 
450  # ExprMem(x, size)[:A] => ExprMem(x, a)
451  # XXXX todo hum, is it safe?
452  elif (isinstance(e.arg, ExprMem) and
453  e.start == 0 and
454  e.arg.size > e.stop and e.stop % 8 == 0):
455  e = ExprMem(e.arg.arg, size=e.stop)
456  return e
457  # distributivity of slice and &
458  # (a & int)[x:y] => 0 if int[x:y] == 0
459  elif (isinstance(e.arg, ExprOp) and
460  e.arg.op == "&" and
461  isinstance(e.arg.args[-1], ExprInt)):
462  tmp = e_s.expr_simp_wrapper(e.arg.args[-1][e.start:e.stop])
463  if isinstance(tmp, ExprInt) and tmp.arg == 0:
464  return tmp
465  # distributivity of slice and exprcond
466  # (a?int1:int2)[x:y] => (a?int1[x:y]:int2[x:y])
467  elif (isinstance(e.arg, ExprCond) and
468  isinstance(e.arg.src1, ExprInt) and
469  isinstance(e.arg.src2, ExprInt)):
470  src1 = e.arg.src1[e.start:e.stop]
471  src2 = e.arg.src2[e.start:e.stop]
472  e = ExprCond(e.arg.cond, src1, src2)
473 
474  # (a * int)[0:y] => (a[0:y] * int[0:y])
475  elif (e.start == 0 and isinstance(e.arg, ExprOp) and
476  e.arg.op == "*" and isinstance(e.arg.args[-1], ExprInt)):
477  args = [e_s.expr_simp_wrapper(a[e.start:e.stop]) for a in e.arg.args]
478  e = ExprOp(e.arg.op, *args)
479 
480  # (a >> int)[x:y] => a[x+int:y+int] with int+y <= a.size
481  # (a << int)[x:y] => a[x-int:y-int] with x-int >= 0
482  elif (isinstance(e.arg, ExprOp) and e.arg.op in [">>", "<<"] and
483  isinstance(e.arg.args[1], ExprInt)):
484  arg, shift = e.arg.args
485  shift = int(shift.arg)
486  if e.arg.op == ">>":
487  if shift + e.stop <= arg.size:
488  return arg[e.start + shift:e.stop + shift]
489  elif e.arg.op == "<<":
490  if e.start - shift >= 0:
491  return arg[e.start - shift:e.stop - shift]
492  else:
493  raise ValueError('Bad case')
494 
495  return e
496 
497 
498 def simp_compose(e_s, e):
499  "Commons simplification on ExprCompose"
500  args = merge_sliceto_slice(e.args)
501  out = []
502  # compose of compose
503  for a in args:
504  if isinstance(a[0], ExprCompose):
505  for x, start, stop in a[0].args:
506  out.append((x, start + a[1], stop + a[1]))
507  else:
508  out.append(a)
509  args = out
510  # Compose(a) with a.size = compose.size => a
511  if len(args) == 1 and args[0][1] == 0 and args[0][2] == e.size:
512  return args[0][0]
513 
514  # {(X[z:], 0, X.size-z), (0, X.size-z, X.size)} => (X >> z)
515  if (len(args) == 2 and
516  isinstance(args[1][0], ExprInt) and
517  args[1][0].arg == 0):
518  a1 = args[0]
519  a2 = args[1]
520  if (isinstance(a1[0], ExprSlice) and
521  a1[1] == 0 and
522  a1[0].stop == a1[0].arg.size and
523  a2[1] == a1[0].size and
524  a2[2] == a1[0].arg.size):
525  new_e = a1[0].arg >> ExprInt(
526  a1[0].start, a1[0].arg.size)
527  return new_e
528 
529  # Compose with ExprCond with integers for src1/src2 and intergers =>
530  # propagage integers
531  # {XXX?(0x0,0x1)?(0x0,0x1),0,8, 0x0,8,32} => XXX?(int1, int2)
532 
533  ok = True
534  expr_cond = None
535  expr_ints = []
536  for i, a in enumerate(args):
537  if not is_int_or_cond_src_int(a[0]):
538  ok = False
539  break
540  expr_ints.append(a)
541  if isinstance(a[0], ExprCond):
542  if expr_cond is not None:
543  ok = False
544  expr_cond = i
545  cond = a[0]
546 
547  if ok and expr_cond is not None:
548  src1 = []
549  src2 = []
550  for i, a in enumerate(expr_ints):
551  if i == expr_cond:
552  src1.append((a[0].src1, a[1], a[2]))
553  src2.append((a[0].src2, a[1], a[2]))
554  else:
555  src1.append(a)
556  src2.append(a)
557  src1 = e_s.apply_simp(ExprCompose(src1))
558  src2 = e_s.apply_simp(ExprCompose(src2))
559  if isinstance(src1, ExprInt) and isinstance(src2, ExprInt):
560  return ExprCond(cond.cond, src1, src2)
561  return ExprCompose(args)
562 
563 
564 def simp_cond(e_s, e):
565  "Common simplifications on ExprCond"
566  # eval exprcond src1/src2 with satifiable/unsatisfiable condition
567  # propagation
568  if (not isinstance(e.cond, ExprInt)) and e.cond.size == 1:
569  src1 = e.src1.replace_expr({e.cond: ExprInt1(1)})
570  src2 = e.src2.replace_expr({e.cond: ExprInt1(0)})
571  if src1 != e.src1 or src2 != e.src2:
572  return ExprCond(e.cond, src1, src2)
573 
574  # -A ? B:C => A ? B:C
575  if (isinstance(e.cond, ExprOp) and
576  e.cond.op == '-' and
577  len(e.cond.args) == 1):
578  e = ExprCond(e.cond.args[0], e.src1, e.src2)
579  # a?x:x
580  elif e.src1 == e.src2:
581  e = e.src1
582  # int ? A:B => A or B
583  elif isinstance(e.cond, ExprInt):
584  if e.cond.arg == 0:
585  e = e.src2
586  else:
587  e = e.src1
588  # a?(a?b:c):x => a?b:x
589  elif isinstance(e.src1, ExprCond) and e.cond == e.src1.cond:
590  e = ExprCond(e.cond, e.src1.src1, e.src2)
591  # a?x:(a?b:c) => a?x:c
592  elif isinstance(e.src2, ExprCond) and e.cond == e.src2.cond:
593  e = ExprCond(e.cond, e.src1, e.src2.src2)
594  # a|int ? b:c => b with int != 0
595  elif (isinstance(e.cond, ExprOp) and
596  e.cond.op == '|' and
597  isinstance(e.cond.args[1], ExprInt) and
598  e.cond.args[1].arg != 0):
599  return e.src1
600 
601  # (C?int1:int2)?(A:B) =>
602  elif (isinstance(e.cond, ExprCond) and
603  isinstance(e.cond.src1, ExprInt) and
604  isinstance(e.cond.src2, ExprInt)):
605  int1 = e.cond.src1.arg.arg
606  int2 = e.cond.src2.arg.arg
607  if int1 and int2:
608  e = e.src1
609  elif int1 == 0 and int2 == 0:
610  e = e.src2
611  elif int1 == 0 and int2:
612  e = ExprCond(e.cond.cond, e.src2, e.src1)
613  elif int1 and int2 == 0:
614  e = ExprCond(e.cond.cond, e.src1, e.src2)
615  return e