assembly - 如何将较小的值弹出到寄存器中

标签 assembly x86 x86-64 cpu-registers

我在堆栈上存储了一个 2 字节值,我想将其弹出到寄存器中。我可以通过使用其中的 16 位寄存器在其中一个通用寄存器上执行此操作,例如:

popw %cx

有没有办法将其放入另一个寄存器(例如r11)并进行零填充?像这样的东西:

popzwq %r11   # making up the syntax

或者什么是正确的方法?

最佳答案

通常,您首先可以通过从不使用pushw来避免这种情况,而是在压入/弹出时始终使用全角(64位)堆栈槽。这也可以保持堆栈对齐。另外,通常您只会在进入/离开函数时使用推送/弹出来保存/恢复寄存器。 (不存在调用保留低位部分但不保留高位字节的调用约定,并且保存/恢复完整寄存器通常是最有效的。)

但如果您确实需要它,只需用 2 条指令来模拟它即可。

   movzwl  (%rsp), %ecx          # or %r11d.  implicitly zero-extends into the full 64-bit reg
   add     $2, %rsp              # or if you need to preserve FLAGS,
                                 # lea 2(%rsp), %rsp

pop 不存在零扩展形式; 8086 只能弹出全角(16 位)寄存器,因此没有现有的操作码需要修改。并且 386 没有引入任何与 movzx 或 movsx 等价的零扩展 pop;几乎没有人会从中受益:普通代码在使用时会使用全角推送/弹出。 (更常见的是当时常见的遗留堆栈参数调用约定,而不是前几个参数的现代高效寄存器参数。) 因此,不值得花费晶体管和操作码编码空间的成本。


或者,如果您不想零扩展,请pop %r11w。 (不确定您是否不知道 r8..r15 的 low-8/low-16/low-32 寄存器的名称,或者为什么您在第二个示例中没有使用 RCX 来与 pop cx 进行对比)。

关于assembly - 如何将较小的值弹出到寄存器中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63651806/

相关文章:

来自 NASM 代码的 Linux64 线程本地存储 (TLS) 数据

assembly - 在 X86 汇编程序中进行提取的最短方法?

assembly - 如何在64位汇编程序中使用RIP相对寻址?

assembly - ROR 打开溢出标志

c - gcc 用 .s 文件编译 .c - .bss 混淆(错误?)

assembly - assembly 中的对齐,每个如何获得其偏移量?

ios - 使用 Parse 的 undefined symbol

algorithm - 这个求平方根算法的名称是什么?

c - 使用内存屏障强制按顺序执行

c - 负值与 rdi 寄存器的比较结果不正确