2013-11-22 4 views
1

Я пытаюсь заменить вызов функции другим. например Вот код с 3-мя функциями - print1, Print2 и главный:llvm заменить функцию другим

#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(); 
} 
}" 

Моя цель состоит в том, чтобы заменить использование print1 (в основной) с Print2. Я компилирую вышеуказанный код в llvm :: Module * (называемый main в коде ниже), а затем создаю из него механизм выполнения.

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

На данный момент, я могу получить все 3 функции (print1, Print2 и основные) от исполнения двигателя и в состоянии выполнить их хорошо. Тем не менее, проблема возникает, когда я пытаюсь заменить функцию «print1» с «Print2», следующим образом:

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. Может кто-то, пожалуйста, сообщите мне, если я последую за правильными шагами, чтобы заменить вызов функции. Если есть другой метод, пожалуйста, дайте мне знать.

thx Vikas.

==========

+2

Может ли компилятор делать какие-либо вставки до этого момента? (Если бы это произошло, 'main' эффективно ввел в него код' print1', и замена функции по имени не смогла бы многое сделать с этим ...) – cHao

+1

Хорошая точка cHao, однако, я не запускать никаких проходов оптимизации или встраивания при компиляции модуля. Он просто построен с использованием процедуры ParseAST (http://clang.llvm.org/doxygen/ParseAST_8h.html), поэтому я предполагаю, что никакой инлайн-операции не произошло. Есть ли способ убедиться, что нет инлайн-событий? – vikas

+1

c Хао, вы были правы. Компилятор действительно вставлял print1. Спасибо за вашу помощь. – vikas

ответ

2

Если компилятор были встраивать print1 в main, функция никогда не будет на самом деле быть называется; Вместо этого main будет иметь свою личную версию кода print1. Так как на самом деле не нужно ссылаться на общий print1, замена в print2 может не повлиять на поведение main.

Если вы хотите проверить, что это проблема (и/или не использовать ее, если она есть), попробуйте сообщить компилятору не встроенную.

Смежные вопросы