Изменение исходного кода во время компиляции (с использованием LLVM)

#include <stdio.h>
#include <string.h>    
int foo(char* a)
    { char str[10];
      if (strlen(a)<10) 
     { 
       sprintf(str,"Yes");
       puts(str);
       return 0;
     }
     else
     {
       sprintf(str,"No");
       puts(str);
       return 1;
     }
    }

Теперь, скажем, при написании прохода LLVM я хочу убедиться, что вместо вызова sprintf вызывается printf (с теми же аргументами). Как я мог это сделать?


person t7t0t0t7t    schedule 24.11.2013    source источник
comment
Это не имеет никакого смысла. Прототипы для sprintf и printf разные. И вы не передаете достаточно аргументов sprintf в своем примере. Чего именно вы пытаетесь достичь?   -  person Jonathon Reinhart    schedule 25.11.2013
comment
Починил это. Я бы предпочел, чтобы один printf() заменил {sprintf()+puts()} через проход LLVM. Я впервые пробую LLVM, мне было интересно, как это можно сделать.   -  person t7t0t0t7t    schedule 25.11.2013


Ответы (2)


В двух словах,

  1. Просмотрите все инструкции в функции.
  2. Если инструкция представляет собой CallInst, проверьте, является ли она вызовом sprintf (вы можете просто проверить ее имя).
  3. Создайте новый CallInst (через CallInst::Create), который вместо этого вызывает printf из sprintf. Я думаю, что самый простой способ получить Value объявления printf — использовать один из методов Module::getOrCreate. Тип printf должен быть таким же, как у sprintf, за вычетом первого параметра.
  4. Установите операнды новых инструкций вызова такими же, как для sprintf, за вычетом первого параметра.
  5. Замените старый вызов новым — replaceInstWithInst (в BasicBlockUtils.h) Пожалуй, самый удобный способ.
  6. Наконец, вы можете захотеть отследить использование старого первого параметра, удалить их все, а затем удалить его, чтобы избавиться от этого вызова puts.
person Oak    schedule 25.11.2013

#ifdef USE_BUFFER
#define my_printf(...) sprintf(buffer, __VA_ARGS__)
#else
#define my_printf(...) printf(__VA_ARGS__)
#endif

Теперь вы можете использовать, например, my_printf("My name is %s.", "Bozo");, и он будет скомпилирован, как если бы он был printf("My name is %s.", "Bozo") по умолчанию.

Если вы включите #define USE_BUFFER перед заголовками, вместо этого эти строки будут преобразованы в sprintf(buffer, "My name is %s.", "Bozo") во время компиляции. Конечно, переменная buffer должна существовать в контексте.

person Havenard    schedule 24.11.2013
comment
Это требует модификации исходного кода перед компиляцией, что, как мне кажется, не похоже на то, о чем просил ОП (хотя это было принято). - person Oak; 25.11.2013