D内联汇编器:函数调用出错 [英] D Inline Assembler: error with function call

查看:100
本文介绍了D内联汇编器:函数调用出错的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了一个非常特殊的问题. 对于VM,我需要将代码从指令函数复制到ubyte数组,然后执行该数组(该技术类似于gcc中的内联宏vm),基本上它的工作原理如下:

I got a very special problem. For a VM I need to copy code from the instruction functions to a ubyte array and then execute this array (the technic is similiar to the inline macro vm in gcc), basically it works like this:

__gshared void * sp = null, sb = null; //stack pointer and stack base

__gshared void add() //the function is just there to access the instruction code
{
    asm{db "INSTRUCTIONCODESTART";} //this is a key to know where the instruction code starts

    //instruction code here (sample instruction add, pops 2 values from the stack and pushes its result)
    sp += 4;
    *cast(uint*)sp += *cast(uint*)(sp - 4);

    asm{db "INSTRUCTIONCODEEND";} //this is a key to know where instruction code ends
}

在Init方法中,每个指令代码都有其自己的缓冲区,并且缓冲区中是INSTRUCTIONCODESTART和INSTRUCTIONCODEEND键之间的每个字节.我通过Windows VirtualProtect调用使该数组可执行.

In the Init method, every instruction code gets its own buffer, and in the buffer is every byte between the INSTRUCTIONCODESTART and the INSTRUCTIONCODEEND key. I make this array executeable through the windows VirtualProtect call.

到目前为止,一切正常,但是当我尝试执行函数调用作为指令时,会出现错误.

So Far, everything works as expected, but when I try to do a function call as an instruction, I will get an error.

__gshared void testcall(){}

__gshared void call()
{
    asm{db "INSTRUCTIONCODESTART";} //this is a key to know where the instruction code starts

    //instruction code here (just calls a D function)
    testcall(); //this somehow throws an error

    asm{db "INSTRUCTIONCODEEND";} //this is a key to know where instruction code ends
}

顺便说一句,我用以下代码测试了指令

Btw I tested the instructions with the following code

void instructiontest()
{
    uint dummy;
    ubyte[] buf = getFunctionCode(&add) ~ 0xC3; //gets code of instruction, appends 0xC3 at it ("ret" instruction, for test purposes only to see if it returns to the D code without errors)
    VirtualProtect(cast(void*)buf, buf.length, PAGE_EXECUTE_READWRITE, &dummy); //makes it executeable
    dummy = cast(uint)&buf[0];
    asm
    {
        call dummy[EBP];
    }
    print("instruction worked without errors!");
}

到目前为止,每条简单的指令(add,mul,sub,push0,push1等)都可以正常工作,但是如果我尝试通过函数调用获取指令代码,则会引发错误

So far, every simple instruction (add, mul, sub, push0, push1, ...) works, but if I try to get the code of an instruction with a function call, it throws an error

对于任何帮助,我都会感到非常高兴和感谢. (顺便说一句,我需要在指令中调用函数以使脚本语言与D通讯)

I would be happy and very thankful about any help. (btw I need function calls in the instruction in order to let the script language communicate with D)

推荐答案

您应该真正地反汇编代码,以清楚地了解代码的作用以及代码为什么被破坏. call函数的反汇编为:

You should really disassemble the code in order to get a clear view of what it's doing and why your code is breaking. The disassembly for your call function is:

0000000000414db8 <_D4test4callFZv>:
  414db8:   55                      push   rbp
  414db9:   48 8b ec                mov    rbp,rsp
  414dbc:   48 83 ec 08             sub    rsp,0x8
  414dc0:   53                      push   rbx
  414dc1:   41 54                   push   r12
  414dc3:   41 55                   push   r13
  414dc5:   41 56                   push   r14
  414dc7:   41 57                   push   r15
  414dc9:   49                      rex.WB
  414dca:   4e 53                   rex.WRX push rbx
  414dcc:   54                      push   rsp
  414dcd:   52                      push   rdx
  414dce:   55                      push   rbp
  414dcf:   43 54                   rex.XB push r12
  414dd1:   49                      rex.WB
  414dd2:   4f                      rex.WRXB
  414dd3:   4e                      rex.WRX
  414dd4:   43                      rex.XB
  414dd5:   4f                      rex.WRXB
  414dd6:   44                      rex.R
  414dd7:   45 53                   rex.RB push r11
  414dd9:   54                      push   rsp
  414dda:   41 52                   push   r10
  414ddc:   54                      push   rsp
  414ddd:   e8 ce ff ff ff          call   414db0 <_D4test8testcallFZv>
  414de2:   49                      rex.WB
  414de3:   4e 53                   rex.WRX push rbx
  414de5:   54                      push   rsp
  414de6:   52                      push   rdx
  414de7:   55                      push   rbp
  414de8:   43 54                   rex.XB push r12
  414dea:   49                      rex.WB
  414deb:   4f                      rex.WRXB
  414dec:   4e                      rex.WRX
  414ded:   43                      rex.XB
  414dee:   4f                      rex.WRXB
  414def:   44                      rex.R
  414df0:   45                      rex.RB
  414df1:   45                      rex.RB
  414df2:   4e                      rex.WRX
  414df3:   44                      rex.R
  414df4:   41 5f                   pop    r15
  414df6:   41 5e                   pop    r14
  414df8:   41 5d                   pop    r13
  414dfa:   41 5c                   pop    r12
  414dfc:   5b                      pop    rbx
  414dfd:   c9                      leave  
  414dfe:   c3                      ret    
  414dff:   90                      nop

414dc9是开始标记的起点,414ddc是结束标记(包括终点). 414de2是结束标记的起点,414df3是结束标记(包括终点)的位置.因此,将其剔除,我们有:

414dc9 is where the start marker begins, 414ddc is where it ends (inclusive). 414de2 is where your end marker begins, 414df3 is where it ends (inclusive). So, ripping that out, we have:

0000000000414db8 <_D4test4callFZv>:
  414db8:   55                      push   rbp
  414db9:   48 8b ec                mov    rbp,rsp
  414dbc:   48 83 ec 08             sub    rsp,0x8
  414dc0:   53                      push   rbx
  414dc1:   41 54                   push   r12
  414dc3:   41 55                   push   r13
  414dc5:   41 56                   push   r14
  414dc7:   41 57                   push   r15
  ; code start marker here
  414ddd:   e8 ce ff ff ff          call   414db0 <_D4test8testcallFZv>
  ; code end marker here
  414df4:   41 5f                   pop    r15
  414df6:   41 5e                   pop    r14
  414df8:   41 5d                   pop    r13
  414dfa:   41 5c                   pop    r12
  414dfc:   5b                      pop    rbx
  414dfd:   c9                      leave  
  414dfe:   c3                      ret    
  414dff:   90                      nop

您显然不会在此处复制一些序言和结语代码.但这本身不应该是个严重的问题.

You're clearly not copying some prologue and epilogue code here. But that, in and of itself, should not be terribly problematic.

我尝试了这个程序:

void main()
{
    foo();
}

void foo()
{
    auto addr = &bar;

    asm { call addr; }
}

void bar()
{
    asm { naked; call baz; ret; }
}

void baz()
{
}

对我有用.坦白说,我不知道你的问题在哪里.您粘贴的大多数代码不能仅复制到源文件中并进行编译,因此很难确定出了什么问题.我希望这里的一些信息可以对您有所帮助.您最有可能必须附加一个调试器,然后找出问题所在.不要期望在不弄脏手的情况下弄乱这样的低级内容. ;)

It works for me. Frankly, I can't tell where your problem is. Most of the code you pasted can't just be copied into a source file and be compiled, so it's quite hard to tell what's going wrong. I hope some of the information here can help you. You're most likely going to have to attach a debugger and find out what's wrong; don't expect to mess with low-level stuff like this without getting your hands dirty. ;)

顺便说一句,我在Linux的64位x86上进行了测试.

BTW, I tested on 64-bit x86 in Linux.

无论哪种方式,您正在做的事情都是高度不可移植的,不确定的,等等.被警告.可能可以解决,但您的保证金为零.

Either way, what you're doing is highly unportable, undefined, etc. Be warned. It may work out, but you're working with zero guarantees.

这篇关于D内联汇编器:函数调用出错的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆