【问题标题】:Move [eax+4] in VS在 VS 中移动 [eax+4]
【发布时间】:2019-11-28 06:27:49
【问题描述】:

我无法编译这个,我应该如何在 Visual Studio 中将 [eax+4] 移动到 y?

float x, y, z;

__asm
{
    mov x,      eax
    mov y,      [eax+4]
    mov z,      [eax+8]
}

编辑:

错误 1 ​​错误 C2424:“+”:“第二个操作数”中的表达式不正确

【问题讨论】:

  • “无法编译”是什么意思?编译器是怎么说的?
  • 你知道[eax+4] 使用EAX 作为指针,对吧?如果eax 拥有一个有效的指针,那么它不太可能也用作float 位模式。我认为这是一个 XY 问题,您可能正在寻找 add eax,4 / cvtsi2ss xmm0, eax / movss y, xmm0

标签: c++ assembly x86 inline-assembly


【解决方案1】:

MOV 指令不能将内存移动到内存。查看您最喜欢的汇编语言参考,了解有关每条指令规则的更多详细信息。如果某事未明确列为允许,则不允许。你不能只是编造一些东西。处理器非常挑剔。

【讨论】:

    【解决方案2】:

    您使用eax 作为指针,因此将该位模式存储到float x 似乎不太可能。也许您的意思是从内存中复制 [eax+0]、+4 和 +8 的 3 个浮点数?

    @RaymondChen 是对的,你可以使用临时寄存器来转移它。显而易见的选择是临时选择 ECX 或 EDX;那些与 EAX 一起被调用破坏的,所以使用它们不会强制编译器在包含你的 asm 块的函数中保存/恢复它们。

    即使值是float,您也可以使用 32 位整数寄存器而不是通过 XMM0 或 x87 寄存器来复制它们;你没有对它们进行 FP 数学运算。

    mov   ecx, [eax]
    mov   x, ecx            // you probably want this, not  mov x, eax
    mov   ecx, [eax+4]
    mov   y, ecx
    mov   ecx, [eax+8]
    mov   z, ecx
    

    如果您知道 xy 是连续的,则可以使用 XMM 寄存器一次复制 8 个字节。

    【讨论】:

    • 位移只有 ebp 和 ebx 才有可能。即使在 16 位中,si 和 di 也可以出现位移而没有 bp 或 bx。
    • Wikipedia 中,有一个清晰的摘要,其中包含 16 位、32 位和 64 位 x86 处理器的所有可能寻址模式。
    • @harold:虽然是正确的,但 esi 和 edi 在那些寻址模式中不称为“base”,而是称为“index”es。也许我应该将其表述为“只允许 ebp 和 ebx 作为位移的基础”。
    • @ssg 那么在 32 位中它仍然不是真的。一切都可以成为基础。
    • @PeterCordes 请随时根据您的喜好编辑我的答案,谢谢。
    【解决方案3】:
    float x, y, z;
    
    __asm
    {
        mov x,      eax
        push        eax
        mov eax,    [eax+4]
        mov y,      eax
        pop         eax
        mov eax,    [eax+8]
        mov z,      eax
    }
    

    【讨论】:

    • 这是对 Sedat 答案的一个小优化,但没有解释,所以这不是一个很好的答案。通过加载到不同的寄存器可以更有效,例如mov edx, [eax+4] 避免了 push/pop 的需要。
    • 确定 mov edx, [eax+4] 会在 push/pop 上节省 2 个字节,但前提是此时不使用 edx,否则你也应该为 edx 进行 push/pop
    • EDX 被呼叫破坏;使用它的功能不需要保存/恢复它。在内联 asm 中使用它可能会使编译器溢出/重新加载它本来会在整个 asm 块中保留在 EDX 中的东西,但很可能不会。此外,大多数时候我们关心的是性能,而不是代码大小,所以重要的是这些指令的 2 个微指令,以及指针在准备好从 [eax+8] 加载之前的额外存储/重新加载延迟。此外,这段代码正在执行大量存储/重新加载,因此这些执行单元将会很忙。
    • EDX 在函数调用的情况下会被调用破坏,以防它必须在 asm 块之外存储/重新加载,并且无论如何 2 次 push/pop 小于 1
    • 所有代码都在 some 函数内。内联后,它可能与源中的函数不同。无论如何,它不必在 asm 块之外存储/重新加载。 MSVC 只会让它被破坏。在此处查看一个真实示例:godbolt.org/z/gecwkE 显示 x86 MSVC 19.22 和 clang 9.0 -O3 -fasm-blocks。如果之后不需要 asm 块之前 EDX 中的任何值,则该值可能会死在那里。无论如何,优化这个 asm 有点疯狂,存储指向 float 的指针是没有意义的,并且使用 MSVC 内联 asm 会强制输入/输出在内存中反弹
    猜你喜欢
    • 1970-01-01
    • 2012-10-10
    • 1970-01-01
    • 1970-01-01
    • 2013-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-21
    相关资源
    最近更新 更多