我使用任意IL构建CFG,并希望将该CFG转换回IL。 CFG中顶点的顺序当然不等于原始IL指令的顺序。
这很好但是过于复杂化了一些东西。想象:
Jump 'B'
'C': Return
'B': Jump 'C'
这将产生如下的流程图:(跳转B) - > (跳转C) - > (返回) 这当然是一个简化的例子,但它显示了转出CFG时的问题。
学术界是否有关于此主题的信息?我认为从底部向上遍历图形会非常优雅,但在更复杂的情况下不起作用。
解决方案可能是自上而下并搜索CF合并,但在这种情况下,我将无法正确处理循环。所以,实现这一目标的唯一方法似乎是在发生可能的CF合并时进行搜索。如果没有,我们必须有一个循环,这意味着首选循环,然后评估继续路径。这听起来像是一个可以解决的问题,但它也非常昂贵,并且可能存在更优雅的问题解决方案。此外,在考虑“中断”语句时,循环也可能导致CF合并。
答案 0 :(得分:2)
将CFG转换为IL:您想要遍历图形,只发射一次每个顶点(除了那些不可达的顶点)。所以你需要记录已经发射的顶点:顶点上的一个标志,或者从顶点到True / False的散列。
有些顶点会有多个后继,你只能直接跟随其中一个;所以你想要一种方法来跟踪你想要稍后回来的顶点。队列适用于此。
这或多或少是我用过的。
def needs_label(cfg, v, last):
if cfg.predecessors(v) > 1:
# There's more than one way of entering this vertex
return True
elif cfg.predecessors(v) == 1 and last != cfg.predecessors(v)[0]:
# There's only one way, but the last vertex emitted was not that way
# so it will be entered using a jump.
return True
else:
return False
def emit_label(v):
print 'label%d' % (v.id)
def emit_vertex(v):
if v.type == 'branch':
# Branch to second successor
print 'br label%d' % cfg.successors(v)[1].id
else:
...
def emit_jump(v):
print 'jmp label%d' % v.id
def emit_cfg(cfg):
q = Queue() # Queue for saving vertices that we want to emit later
done = {} # Hash recording which vertices have already been emitted
q.push(cfg.start())
while not q.empty():
v = q.pop()
last = None
while v is not None and not done[v]:
# Emit the vertex, with a prefixed label if necessary
if needs_label(cfg, v, last):
emit_label(v)
emit_vertex(v)
done[v] = True
last = v
# Get the vertex's successors
succs = cfg.successors(v)
# If there aren't any, then this path is finished, so go back to
# the outer loop to pop another saved vertex
if len(succs) == 0:
v = None # Setting this will terminate the inner loop
continue
# Stick all the vertices on the stack for later, in case we can't
# process them all here
for s in succs:
q.push(s)
# Pick a new vertex from the list of successors. Always pick the first
# because if it's a branch then the second will have been branched on
v = succs[0]
# If it was emitted earlier we need to jump to it
if done[v]:
emit_jump(v)
v = None
# Otherwise continue the inner loop, walking from the new vertex
对分支(具有多个后继的顶点)的处理非常幼稚:通常你想要找出哪个更有可能并且如果可能的话直接跟随那个。
答案 1 :(得分:0)
这比听起来容易。基本上可以去除CFG中的任何跳转语句,从而产生优化的图形。一旦图形线性化,将插回跳转语句。这不保留指令的原始顺序,但会产生具有相同控制流的方法。