Получить ptr из вызова функции asmjit

Я пытаюсь сгенерировать вызов функции используя AsmJit к которому я передаю char*, это char* сам по себе извлекается из другого вызова функции. Я опробовал это:

typedef
const char* getStr();

const char* getStrImpl()  {
return "hello pie";
}

void use_str_impl(int id, const char* c_str) {
// do stuff...
}

int main() {
JitRuntime rt;
CodeHolder code;
code.init(rt.getCodeInfo());

X86Compiler c(&code);

auto jitted_func = c.addFunc(FuncSignature0<const char*>(code.getCodeInfo().getCdeclCallConv()));
auto err = c.getLastError();

auto call = c.call((uint64_t) fooFuncImpl, FuncSignature0<intptr_t>());
X86Gpd res(call->getRet().getId());

auto call2 = c.call((uint64_t) send_input, FuncSignature2<void, int, intptr_t>());
err = !call2->setArg(0, Imm(42));
err = !call2->setArg(1, res);

c.ret();

c.endFunc();
err = c.finalize();

if(err) return 0;

size_t size = code.getCodeSize();
VMemMgr vm;

void* p = vm.alloc(size);
if (!p) return 0;

code.relocate(p);
auto fun = (entrypoint*) p;
fun();
}

Оказывается, это не генерирует никаких инструкций для второго параметра или второго вызова setArg, Я также пытался использовать .newIntPtr и используя инструкции перемещения, чтобы переместить результат вызова на место. Но это породило dec и добавить инструкции, которые не имели смысла для меня и моего небольшого опыта сборки. Как правильно делать такие вещи?

Кстати, я использую следующую ветку AsmJit.

0

Решение

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


Лучшее использование JitRuntime:

JitRuntime rt;
size_t size = code.getCodeSize();
VMemMgr vm;
....
void* p = vm.alloc(size);
if (!p) return 0;
code.relocate(p);
auto fun = (entrypoint*) p;

Вы использовали JitRuntime просто для настройки параметров CodeHolder, но затем избежали этого и самостоятельно распределили память для функции. Хотя это правильный вариант использования, это не то, что делает большинство людей. Использование времени выполнения add() достаточно в большинстве случаев.


Неправильное использование CCFuncCall :: getRet ():

X86Gpd res(call->getRet().getId());

call узлу в этой точке не назначен регистр возврата, поэтому он будет возвращать неверный идентификатор. Если вам нужно создать виртуальный регистр, вы всегда должны вызывать компилятор newSomething(), Компилятор AsmJit предоставляет API для проверки этого случая во время выполнения, если вы не уверены:

// Would print 0
printf("%d", (int)c.isVirtRegValid(call->getRet().getId()));

Решение состоит в том, чтобы создать новый виртуальный регистр и присвоить его возвращаемому значению функции. Для присвоения возвращаемого значения требуется индекс (например, назначение аргумента), причина в том, что некоторые функции могут возвращать несколько значений (например, 64-битное значение в 32-битном режиме), при этом в большинстве случаев достаточно использовать 0 в качестве индекса.

X86Gp reg = c.newIntPtr("reg");
call->setRet(0, reg);

Вы можете проверить getRet() функциональность:

X86Gp reg = c.newIntPtr("reg");
assert(call->getRet(0).isNone());
call->setRet(0, reg);
assert(call->getRet(0) == reg);

Полностью рабочий пример:

#include <stdio.h>
#include <asmjit/asmjit.h>

const char* func_a() {
printf("func_a(): Called\n");
return "hello pie";
}

void func_b(int id, const char* c_str) {
printf("func_b(%d, %s): Called\n", id, c_str);
}

int main() {
using namespace asmjit;

JitRuntime rt;

CodeHolder code;
code.init(rt.getCodeInfo());

X86Compiler c(&code);
X86Gp reg = c.newIntPtr("reg");

// Compilation step...
c.addFunc(FuncSignature0<void>(code.getCodeInfo().getCdeclCallConv()));

auto call_a = c.call((uint64_t)func_a, FuncSignature0<intptr_t>());
call_a->setRet(0, reg);

auto call_b = c.call((uint64_t)func_b, FuncSignature2<void, int, intptr_t>());
call_b->setArg(0, Imm(42));
call_b->setArg(1, reg);

c.ret();
c.endFunc();

// Finalize does the following:
//   - allocates virtual registers
//   - inserts prolog / epilog
//   - assembles to CodeHolder
auto err = c.finalize();
if (err) {
printf("COMPILER FAILED: %s\b", DebugUtils::errorAsString(err));
return 1;
}

typedef void (*EntryPoint)(void);
EntryPoint entry;

// Adds function to the runtime. Should be freed by rt.release().
// Function is valid until the runtime is valid if not released.
err = rt.add(&entry, &code);
if (err) {
printf("RUNTIME FAILED: %s\b", DebugUtils::errorAsString(err));
return 1;
}

entry();
return 0;
}
0

Другие решения

Других решений пока нет …