1

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

__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 调用使这个数组可执行。

到目前为止,一切都按预期工作,但是当我尝试将函数调用作为指令进行时,我会收到错误消息。

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

顺便说一句,我使用以下代码测试了说明

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、...)都有效,但如果我尝试通过函数调用获取指令的代码,则会引发错误

我会很高兴并且非常感谢任何帮助。(顺便说一句,我需要在指令中调用函数,以便让脚本语言与 D 通信)

4

2 回答 2

2

您应该真正反汇编代码,以便清楚地了解它在做什么以及为什么您的代码会被破坏。您的功能的反汇编call是:

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的地方,是结束的地方(包括)。所以,撕掉它,我们有:

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

您显然不是在这里复制一些序言和尾声代码。但是,就其本身而言,这不应该是非常有问题的。

我试过这个程序:

void main()
{
    foo();
}

void foo()
{
    auto addr = &bar;

    asm { call addr; }
}

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

void baz()
{
}

这个对我有用。坦率地说,我不知道你的问题出在哪里。您粘贴的大多数代码不能只是复制到源文件中并进行编译,因此很难判断出了什么问题。我希望这里的一些信息可以帮助到你。您很可能必须附加调试器并找出问题所在;不要指望在不弄脏手的情况下弄乱这样的低级东西。;)

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

无论哪种方式,您所做的都是高度不可移植、未定义等。请注意。它可能会奏效,但您正在使用零保证。

于 2012-07-15T12:12:31.227 回答
0

如果没有看到所有相关代码的完整反汇编,很难说出所有错误是什么,但是......

  1. x86 代码通常不是与位置无关的,这意味着将其复制到不同的位置并在那里执行它可能而且通常会失败。

  2. 您最有可能复制破坏寄存器(包括ebpand esp)和堆栈内容的代码。

于 2012-07-15T11:27:29.263 回答