【问题标题】:D Inline Assembler: error with function callD 内联汇编程序:函数调用出错
【发布时间】:2012-07-15 11:19:39
【问题描述】:

我遇到了一个非常特殊的问题。 对于虚拟机,我需要将指令函数中的代码复制到一个 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 通信)

【问题讨论】:

  • 仅供参考:__gshared 对函数没有影响,只有变量。

标签: assembly call d inline-assembly


【解决方案1】:

您应该真正反汇编代码,以便清楚地了解它在做什么以及为什么您的代码会被破坏。 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 上进行了测试。

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

【讨论】:

  • 其实你的反汇编对我帮助很大,如果我将“call testcall”复制到另一个内存位置,相对跳转将无法正常工作,所以我的解决方案是不要将代码复制到新的位置,但是要围绕指令代码创建一个类 Wrapper(在我的密钥之后保存地址),所以我只是跳转到我的指令密钥之后的地址,它现在可以工作了
【解决方案2】:

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

  1. x86 代码通常不是位置独立的,这意味着将其复制到不同的位置并在那里执行它可能会并且大多数情况下会失败。

  2. 您很可能是在复制破坏寄存器(包括ebpesp)和堆栈内容的代码。

【讨论】:

  • 好吧,我确保我不使用任何局部变量(每个变量都用 __gshared 声明,这意味着它在某处有一个静态位置,因此 ebp 寄存器不会被损坏),以及一个函数调用一个空函数应该反汇编成“call testcall”之类的东西,还是我错了?
  • 我不知道,因为我没有看到所有相关的代码都被反汇编了。
猜你喜欢
  • 1970-01-01
  • 2011-01-14
  • 1970-01-01
  • 1970-01-01
  • 2011-03-08
  • 1970-01-01
  • 2011-12-20
  • 2011-05-27
  • 1970-01-01
相关资源
最近更新 更多