我有一些表达式为a=b+c-d*e
,在LLVM传递的帮助下,我想创建一个像这样的字符串
“['b'的十六进制地址] [+的操作码] ['c'的十六进制地址] [ - 的代码 - ] [d'的十六进制地址] [*的操作码] ['e'的十六进制地址]”。
我怎么能这样做。
答案 0 :(得分:2)
首先,请记住变量不一定存在于内存中;它们可以存储在寄存器中或完全省略。在LLVM IR的上下文中,它意味着该值将直接从另一个值使用(没有存储或加载)。
假设所涉及的所有变量都需要从内存中加载,我可以想到的最简单的方法是找到store
,然后通过操作数向后执行后序DFS,记录操作码,并在识别负载时停止。对于你提供的片段,它应该给你b加载,然后加上操作码,然后是c的加载,然后是负操作码等。
现在您已经有了这样的序列,我想说从中生成字符串的最简单方法是使用动态构建的格式字符串插入对C sprintf
的调用,并将指针传递给它找到了(来自load
)。
我看到上述两个问题:
这里存在一些固有的歧义 - 只是以这种方式访问它们无法区分,例如(b+c-d)*e
与b+(c-d)*e
。所以我认为只要你输入算术指令并分别留下它就记录“(”和“)”是有意义的。
此方法实际上并未检查所有操作是否为同一表达式的一部分。因此,如果您有tmp = b+c; a = tmp-d*e;
,并且tmp
被优化掉了,那么它在IR中看起来会相同。我可以想到强制执行的唯一方法是使用调试符号进行编译并挖掘那些以识别不同的表达式 - 尽管我不知道这是否可行 - 或实际上修改Clang来记录表达式边界:\
这种方法的伪代码(简单的序列处理操作):
functionPass:
for each instruction:
if instruction is store:
processExpression(store)
processExpression(store):
sequence <- initialize
visit(sequence, store.value)
generateSprintfCallFromSequence(sequence)
visit(sequence, value):
if value is load:
sequence.add(load.pointer)
else if value is binaryop:
// sequence.add(openingParen)
visit(sequence, binaryop.operand(0))
sequence.add(binaryop.opcode)
visit(sequence, binaryop.operand(1))
// sequence.add(closingParen);