用LLVM替换一个函数为另一个函数

3

我将尝试用另一个函数替换一个函数调用。比如下面的代码中有三个函数:print1、print2和main:

#include <stdio.h>
extern "C" { 
int print1()
{
   printf("Inside print1\n");
   return 0xdeadbeef;
}
int print2()
{
   printf("Inside print2\n");
   return 0xbeefdead;
}
int main(void)
{
   return print1();
}
}"

我的目标是用print2来替换在主函数中使用的print1。我将上述代码编译成一个名为“main”的llvm::Module*,然后创建一个执行引擎。

std::string errMsg;
llvm::ExecutionEngine *ee =
   llvm::EngineBuilder( main ).setErrorStr( &errMsg ).create();    
ASSERT_NE( ee, nullptr )<<"Execution engine is nullptr:"<<errMsg;

此时,我可以从执行引擎中获取所有 3 个函数 (print1、print2 和 main),并且可以正常执行它们。然而,当我尝试用“print2”替换函数“print1”时,问题就出现了,如下所示:

llvm::Function *print1f = main->getFunction( "print1" );
llvm::Function *print2f = main->getFunction( "print2" );
llvm::Function *mainf = main->getFunction( "main" );

//carry out the replacement
print2f->takeName( print1f );
ee->freeMachineCodeForFunction( mainf );
ee->freeMachineCodeForFunction( print1f );
print1f->replaceAllUsesWith( print2f );
print1f->deleteBody();
print1f->dropAllReferences();
print1f->eraseFromParent();

//run main
void *mainfPtr = ee->getPointerToFunction( mainf );
mainfPtr = ee->recompileAndRelinkFunction( mainf );
ASSERT_NE( mainfPtr, nullptr );
ret = ((int(*)(void))(mainfPtr))();
*EXPECT_EQ(0xbeefdead, ret);*

然而,ret返回为0xdeadbeef,就像是调用print1而不是print2一样。请问是否有人能告诉我是否按照正确步骤替换了函数调用?如果有其他方法,请告诉我。
谢谢, Vikas。

2
编译器能在此时点之前进行任何内联优化吗? (如果这样做了,“main”实际上将会把“print1”的代码粘贴进去,替换函数名称并不能做太多事情...) - cHao
1
不错的观点cHao,但是我在编译模块时没有运行任何优化通道或内联操作。它只是使用ParseAST例程(http://clang.llvm.org/doxygen/ParseAST_8h.html)简单构建的,因此我猜测没有内联发生。有什么方法可以确保不会发生内联吗? - vikas
1
cHao,你是对的。编译器确实将print1内联了。感谢你的帮助。 - vikas
cHao,看起来我无法将评论作为答案接受。请将您的评论发布为答案,我会接受它。 - vikas
1个回答

4
如果编译器在main中内联print1,那么该函数实际上将永远不会被调用;相反,main将有自己私有的print1代码版本粘贴进去。由于它实际上不必再引用共享的print1,所以替换为print2可能不会影响main的行为。
如果您想验证这是否是问题(或者如果是,则防止发生),请尝试告诉编译器不要内联。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接