最近我正在尝试修改GCC和gcov以收集程序的执行顺序。众所周知,gcc会在基本块之间的弧上设置代码来计算弧的执行次数。所以我在弧上设置一个函数,函数将打印出该弧的no,所以我可以收集程序执行序列。它适用于x86和x86_64上的c程序,也适用于x86的c ++程序。但对于x86_64上的c ++程序,程序将因段错误而崩溃。编译没有问题。我使用的操作系统是CentOS 6.4。 gcc的版本是3.4.5。有人有什么建议吗?
示例程序:
#include <iostream> using namespace std; int main(){cout<<"hello world"<<endl;}
如果我在x86_64模式下编译程序。来到cout CALL时,程序会因Segment Error而崩溃。
答案 0 :(得分:0)
好的,经过另一个晚上调试就可以了。我发现函数emit_library_call只生成asm代码来调用我的函数,但不保护上下文(寄存器)。因此,在发出的代码之前或之后的函数调用可能由于非均匀的上下文而失败。 x86_64 asm使用与x86不同的寄存器。因此,在x86平台上运行良好可能只是偶然。我需要一个函数api,它可以发出库函数调用并保护上下文。也许我应该写另一个emit_library_call。
答案 1 :(得分:0)
也许您可以尝试动态二进制翻译框架,例如DynamoRIO或Pin。这些工具提供了比您需要的更多灵活性,但它们允许您在每个基本块的开头/结尾注入代码。你想要做的是保存/恢复标志和寄存器(并可能重新对齐堆栈),然后调用函数。 DynamoRIO内置了类似的功能,称为“干净呼叫”。我认为Pin还可以通过更高级别的接口来实现这一点。
答案 2 :(得分:0)
我在3.5.0-23-generic #35~precise1-Ubuntu SMP Fri Jan 25 17:13:26 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
#include <iostream>
`using namespace std;
int main()
{
cout<<"hello world"<<endl;
}`
使用g++ -ftest-coverage -fprofile-arcs hello.cpp -o hello
编译上面的代码
生成hello.gcno
文件。
执行./hello hello.gcda
文件后生成。
所以一旦检查你的gcc版本。
我的gcc版本为gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)