Как сгенерировать код для инициализации глобальных переменных неконстантными значениями в LLVM?

Как в LLVM (в частности, llvmlite) объявить глобальную переменную и инициализировать ее содержимое результатом произвольного выражения (во время выполнения)?

Я вижу, что могу создать объект GlobalVariable, но похоже, что его аргумент initializer ожидает Constant. Что, если мне нужно запустить произвольный код во время запуска/загрузки, чтобы определить его значение? Куда идет этот код? К чьему Builder добавить инструкции? Нужно ли объявлять функцию со специальным именем и/или добавлять к ней магические атрибуты, чтобы она автоматически выполнялась, когда модуль загружается в память во время выполнения?


person trbabb    schedule 02.08.2017    source источник
comment
Предположительно, вы можете заставить clang сделать пример для вас, если вы напишете C++ как int nc_global = foo(); и скажете ему испускать LLVM-IR.   -  person Peter Cordes    schedule 01.11.2020


Ответы (3)


Это полностью зависит от вашей настройки. В C или C++ с Visual Studio функции инициализации C и C++ помещаются в подраздел раздела .CRT и выполняются стандартной библиотекой времени выполнения.

Если вы компилируете без CRT и имеете эти функции инициализации, они не сработают, потому что об этом позаботится среда выполнения.

Исправление: отображается @llvm.global_ctors существует.

Я не уверен, что они будут работать правильно в среде без библиотеки времени выполнения, которая помогает выполнять инициализаторы, но вот она.

person keyboardsmoke    schedule 02.08.2017

Вы можете сохранить инициализатор выражения в глобальной переменной из основной функции.

// all LLVM includes
using namespace std;

LLVMContext context;
Module* module = new Module("module_1", context);
IRBuilder<> builder(context);
SymbolTable symbolTable; // some structure to map the symbol names to the LLVM value

// ...

Value* createGlobalVar(const string& id, Type* type, Value* init) {
    Value* gv = new GlobalVariable(*module, type, false, GlobalValue::PrivateLinkage, Constant::getNullValue(type), id);

    Function* mainFunc = symbolTable.get("main");
    BasicBlock* entryBB = &(mainFunc->getEntryBlock());

    BasicBlock* currentBB = &(builder.GetInsertBlock());
    auto currentInsertPoint = builder.GetInsertPoint(); // returns an iterator
    builder.SetInsertPoint(entryBB, entryBB->begin());
    builder.CreateStore(init, gv);
    builder.SetInsertBlock(currentBB, currentInsertPoint);
    symbolTable.add(id, gv);
    return gv;
}

Хотя вы собираетесь заменить начальное значение произвольным выражением, у GlobalVariable должен быть инициализатор, указывающий, что он принадлежит текущему модулю. В противном случае ожидается некоторая связь с некоторой существующей переменной.

Я написал эту функцию, думая, что ваше объявление глобальной переменной можно найти в любом месте кода. Однако если вы генерируете код из абстрактного синтаксического дерева (AST), скорее всего, ваше объявление будет отображаться перед основным объявлением, то есть до того, как main будет вставлен в таблицу символов. В этом случае вы можете создать глобальную переменную и вставить ее в таблицу символов, а также создать инструкцию сохранения после завершения всего анализа.

person Rafael Rodrigues dos Santos    schedule 28.11.2018

Ссылка на ответ @keyboardsmoke:

Вы можете сгенерировать llvm.global_ctors с помощью TransformUtils.

#include "llvm/Transforms/Utils/ModuleUtils.h"
Function* globalInitFunction = llvm::getOrCreateInitFunction(*TheModule, "_VarDeclInitializations");
// add basic block to give body to _VarDeclInitializations, etc.
person Lenny    schedule 01.11.2020