【发布时间】:2011-10-18 11:45:59
【问题描述】:
我想编写一个 LLVM pass 来检测每个内存访问。 这就是我想要做的。
给定任何 C/C++ 程序(如下面给出的程序),我试图在每条读取/写入内存的指令之前和之后插入对某个函数的调用。例如考虑下面的 C++ 程序 (Account.cpp)
#include <stdio.h>
class Account {
int balance;
public:
Account(int b)
{
balance = b;
}
~Account(){ }
int read()
{
int r;
r = balance;
return r;
}
void deposit(int n)
{
balance = balance + n;
}
void withdraw(int n)
{
int r = read();
balance = r - n;
}
};
int main ()
{
Account* a = new Account(10);
a->deposit(1);
a->withdraw(2);
delete a;
}
所以在检测之后我的程序应该是这样的:
#include <stdio.h>
class Account
{
int balance;
public:
Account(int b)
{
balance = b;
}
~Account(){ }
int read()
{
int r;
foo();
r = balance;
foo();
return r;
}
void deposit(int n)
{
foo();
balance = balance + n;
foo();
}
void withdraw(int n)
{
foo();
int r = read();
foo();
foo();
balance = r - n;
foo();
}
};
int main ()
{
Account* a = new Account(10);
a->deposit(1);
a->withdraw(2);
delete a;
}
其中 foo() 可以是任何函数,例如获取当前系统时间或增加计数器 .. 等等。
请给我示例(源代码、教程等)以及如何运行它的步骤。我已经阅读了http://llvm.org/docs/WritingAnLLVMPass.html 上关于如何制作 LLVM 通行证的教程,但无法弄清楚如何为上述问题编写通行证。
【问题讨论】:
-
好吧,您可能会重载运算符,使其不仅执行实际的加法、减法、赋值函数,还可以调用您的自定义函数。
-
为什么要添加这些功能?如果你想调试你的程序,有更好的方法可用。
-
在您的示例中,您错过了很多潜在的内存访问(函数调用、指针取消引用、变量读取等)。实际上,IR 代码的每条指令都可能访问内存,在生成最终程序集之前您无法确定。检测每条 IR 线绝对是个坏主意,像 valgrind 这样的工具可能更适合您的问题。您能否详细介绍一下您要完成的工作?
-
@SK-logic,我的理解是 CPU 的寄存器数量有限,并且可能没有足够的寄存器来存储您正在使用的所有值。在这种情况下,编译器必须将其中一个寄存器写入内存(堆栈)以腾出空间。这是在取决于目标架构的寄存器分配过程中确定的。因为这个 pass 是在将 IR 代码转换为汇编时执行的,所以仅通过查看 IR 代码很难确定一个值是从内存中写入还是从内存中读取。
-
@Ze Blob,我怀疑有人会对检测堆栈帧访问感兴趣。无论如何,这些操作的顺序是不能保证的,LLVM 会重新洗牌没有副作用(甚至可以在基本块中这样做),所以在每条指令周围添加一些东西是没有意义的。
标签: c++ c static-analysis instrumentation