简体   繁体   English

从函数调用 asmjit 中检索 ptr

[英]Retrieve ptr from function call asmjit

I am trying to generate a function call using AsmJit to which I pass an char* .我正在尝试使用AsmJit生成一个函数调用,我将一个char*传递给它。 This char* is in itself retrieved from another function call.这个char*本身是从另一个函数调用中检索的。 I tried out this:我试过这个:

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

It turns out this does not generate any instructions for the second parameter or second call to setArg .事实证明,这不会为第二个参数或第二次调用setArg生成任何指令。 I also tried to use .newIntPtr and using move instructions to move the result of call into place.我还尝试使用.newIntPtr并使用移动指令将调用结果移动到位。 But this generated dec and add instructions which made no sense to me and my small experience with assembly.但这产生了dec和 add 指令,这对我和我在汇编方面的小经验毫无意义。 What is the correct way of doing this type of thing?做这种事情的正确方法是什么?

Btw I am using the AsmJit next branch.顺便说一句,我正在使用 AsmJit next 分支。

I have done few corrections to your sample with some comments.我对您的样本做了一些更正,并附有一些评论。


Better Usage of JitRuntime:更好地使用 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;

You have used JitRuntime just to setup the parameters for CodeHolder, but then avoided it and allocated the memory for the function yourself.您使用 JitRuntime 只是为 CodeHolder 设置参数,但随后避免使用它并自己为函数分配内存。 While that's a valid use case it's not what most people do.虽然这是一个有效的用例,但它不是大多数人所做的。 Using runtime's add() is sufficient in most cases.在大多数情况下,使用运行时的add()就足够了。


Invalid use of CCFuncCall::getRet():无效使用 CCFuncCall::getRet():

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

The call node at this point doesn't have any return register assigned so it would return an invalid id.此时的call节点没有分配任何返回寄存器,因此它将返回无效的 id。 If you need to create a virtual register you always have to call compiler's newSomething() .如果您需要创建一个虚拟寄存器,您总是必须调用编译器的newSomething() AsmJit's compiler provides API to check for that case at runtime, if you are unsure: AsmJit 的编译器提供 API 来在运行时检查这种情况,如果您不确定:

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

The solution is to create a new virtual register and ASSIGN it to the function's return value.解决方案是创建一个新的虚拟寄存器并将其分配给函数的返回值。 Assigning return value requires an index (like assigning an argument), the reason is that some functions may return multiple values(like 64-bit value in 32-bit mode), using 0 as index is sufficient most of the time.分配返回值需要一个索引(如分配参数),原因是某些函数可能返回多个值(如 32 位模式下的 64 位值),大多数情况下使用 0 作为索引就足够了。

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

You can verify getRet() functionality:您可以验证getRet()功能:

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

Fully working example:完全工作的例子:

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

I am trying to create a function that receives and returns a double.我正在尝试创建一个接收并返回双精度值的函数。 For the call method I used the approach with Mem.对于调用方法,我使用了 Mem 的方法。 At the end I need to save the result in the variable xmm1.最后,我需要将结果保存在变量 xmm1 中。

I can't identify the error.我无法识别错误。 The sine function is called correctly.正弦函数被正确调用。 But for the final assembler generation error occurs.但是对于最终的汇编器生成会出现错误。

        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;

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM