从函数调用asmjit中检索ptr

时间:2016-12-17 12:06:45

标签: c++ 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下一个分支。

3 个答案:

答案 0 :(得分: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节点没有分配任何返回寄存器,因此它将返回无效的id。如果需要创建虚拟寄存器,则必须始终调用编译器newSomething()。如果您不确定,AsmJit的编译器提供了在运行时检查该情况的API:

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

解决方案是创建一个新的虚拟寄存器并将其指定给函数的返回值。分配返回值需要索引(如分配参数),原因是某些函数可能返回多个值(如32位模式下的64位值),使用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;
}

答案 1 :(得分:0)

我正在尝试创建一个接收并返回双精度值的函数。对于调用方法,我对Mem使用了该方法。最后,我需要将结果保存到变量xmm1中。

我无法识别错误。正弦函数被正确调用。但是对于最终的汇编器生成错误。

        JitRuntime rt;
        CodeHolder code;
        code.init(rt.codeInfo());

        asmjit::x86::Compiler cc(&code);
        asmjit::x86::Gp reg = cc.newIntPtr("reg");

        asmjit::Zone zonee(1024);
        asmjit::ConstPool constPool(&zonee);
        asmjit::Label constPoolLabel = cc.newLabel();


        // Compilation step...
        // c.addFunc(asmjit::FuncSignatureT<void>(code.codeInfo().getCdeclCallConv()));
        cc.addFunc(asmjit::FuncSignatureT<void>());


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

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

        auto seno = [&](double value) {
            size_t valueOffset;
            double seno = static_cast<double_t>(std::sin(value));
            cout << " seno " << seno << endl;
            constPool.add(&seno, sizeof(double), valueOffset);
            return asmjit::x86::ptr(constPoolLabel, valueOffset);
        };

        asmjit::x86::Mem mem;
        double test = 180.5;
        auto call_c = cc.call(seno(test), asmjit::FuncSignatureT<double_t>());
        call_c->setArg(0, asmjit::Imm(test));
        call_c->_setRet(0, mem);

        cc.movsd(asmjit::x86::xmm1, mem);

        cc.ret();
        cc.endFunc();

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

        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;
        }

        entry();
        return;

答案 2 :(得分:0)

也许内存对象应该与某个内存地址相关?

Mem mem = qword_ptr ((uint64_t) &test);