【问题标题】:Confused how to access C++ variable within assembly code困惑如何在汇编代码中访问 C++ 变量
【发布时间】:2020-05-11 03:28:08
【问题描述】:

参加汇编课程,所有编程都是在 Visual Studio 中使用 _asm 命令完成的。这是我正在处理的作业的模板:

void main ()
    {
    const unsigned char c1 (0x11);
    const unsigned char c2 (0x22);
    const unsigned char c3 (0x33);
    const unsigned char c4 (0x44);
    unsigned long i1 (0);
    _asm
        {
        **CODE HERE**
        }
     cout << "result is " << hex << i1 << endl;
    }

说明:在 _asm 关键字表示的块内,添加代码将 c1、c2、c3 和 c4 的值(每个 8 位)放入 eax 寄存器,其中 c1 加载在高位(最高有效端)和c4在低端。将 32 位结果放入 i1。

如何访问在 C++ 中声明的变量?我认为汇编中没有“变量”之类的东西,那么我应该如何访问这些变量?

【问题讨论】:

  • 你只是access it by name。您不是在编写纯程序集,而是在编写 MSVC 嵌入式程序集。
  • 您的 asm 能否利用它们是常量这一事实,并使用在编译时计算立即数的一条指令执行 mov eax, (c1&lt;&lt;24) | (c2&lt;&lt;16) | ...?还是您必须让 MSVC 将它们放入内存中,然后 mov al, c1 并转移? (或者任何其他不涉及写入部分寄存器的方法?)

标签: c++ visual-studio assembly inline-assembly


【解决方案1】:

使用 Visual Studio 添加这些数字的示例。

#include <iostream>

int main( )
{
    const unsigned char c1 (0x11);
    const unsigned char c2 (0x22);
    const unsigned char c3 (0x33);
    const unsigned char c4 (0x44);
    unsigned long i1 (0);
    _asm
    {
            xor     eax,eax
            xor     ecx,ecx         ;xor and mov could be replaced with movzx ecx,c1
            mov     cl,c1
            add     eax,ecx
            mov     cl,c2
            add     eax,ecx
            mov     cl,c3
            add     eax,ecx
            mov     cl,c4
            add     eax,ecx
            mov     i1,eax
    }
    std::cout << "result is " << std::hex << i1 << std::endl;
    return 0;
}

请注意,64 位程序中不允许内联汇编,这需要单独的源文件才能将汇编代码与 C 或 C++ 代码混合。

【讨论】:

  • 这计算c1+c2+c3+c4,而不是将这些字节打包成一个双字作为c1:c2:c3:c4。不过,这是一个如何在不为它们做 OP 作业的情况下访问变量的示例。 (您可以使用movzx ecx, c1 来避免先对ECX 进行异或归零)
  • @PeterCordes - |xor ecx|mov cl,c1| 的时钟或微指令数呢? vesus |movzx ecx,c1| ?丢失了描述代码的编辑,现在已修复。
  • movzx r32, m8 是单 uop,甚至在很长一段时间内都没有在 Intel 上进行微融合(完全由加载端口处理)。根据uops.info,Zen 1 和 Zen 2 也是如此。与 32 位 mov 加载相同的延迟。每次加载会花费 1 个额外字节的代码大小,但是让每次加载都写入完整的寄存器会消除加载之间的串行依赖关系,以及任何合并 uop 的需要。
  • 异或置零将避免写入cl和读取ecx的任何部分寄存器惩罚(例如P6系列或早期SnB)(除非在置零和mov r8,m8之间出现中断所以保存/恢复 reg 会破坏它。)但在现代英特尔(HSW 及更高版本,不会将 cl 与 ECX 分开重命名)mov cl, mem 花费 1 micro-fused 加载+合并 uop。它作为单个微指令通过前端,但在后端必须执行 ALU 微指令以将加载结果合并到 ECX 中,然后add 才能读取它。所以它在 RS 中占用更多空间,并且延迟更多(在短的独立链中)
  • 经验法则:只有在您特别想要合并到前一个值的低字节时才使用mov r8, ...。否则,请使用类似 RISC 的零扩展或符号扩展加载样式。 (某些 CPU(可能像 AMD Bulldozer?)需要额外的 uop 来对字节或字加载进行符号扩展;最近的 Intel / AMD 也纯粹在加载端口中加载 movsx。)在某些情况下,可以节省 1 个字节的代码尺寸更有用,例如在其自身性能并不重要的冷代码中,或者如果您知道对于您的目标 CPU,部分注册的东西可以正常工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-09
  • 1970-01-01
  • 1970-01-01
  • 2022-12-10
  • 2023-02-17
  • 1970-01-01
相关资源
最近更新 更多