【问题标题】:YASM logical right shift zeroing out memory?YASM逻辑右移归零内存?
【发布时间】:2021-09-20 21:28:54
【问题描述】:

我正在使用 YASM 汇编程序。

如果我有一个这样声明的变量

segment .bss
 number resb 100

我像这样执行逻辑右移

shr byte [number], 8

如果例如 123 存储在那里,那么内存看起来像这样 0x333231 然后我希望结果是 0x3332,但结果是 0x333200。如果我将数据存储在寄存器中,则不会发生此问题,谁能向我解释为什么会发生这种情况以及如何解决它(我想使用内存而不是寄存器)。

【问题讨论】:

  • 你使用了byte操作数大小,所以你只对低字节进行操作,移出所有8位。如果您执行shr al, 8,您将得到相同的结果,而 RAX 的高 7 字节不受影响。
  • 请注意,一条shr 指令最多可以影响您使用resb 100 保留的100 个字节中的8 个字节(qword);您将需要扩展精度的东西(例如shrd)将该空间作为单个 100 字节整数处理。或者,也许您打算将该空间视为由 25 个 dword 元素组成的数组? IDK。
  • 相关,但从另一个角度提出问题(如果操作更宽,则不会影响高字节,例如不携带的增量):Why do we need to disambiguate when adding an immediate value to a value at a memory address

标签: assembly x86 yasm


【解决方案1】:

例如 123 存储在那里,因此内存看起来像这样的 0x333231

看到值 0x333231,我敢假设 number 处的内存以 ASCII 表示形式保存数字。

31 32 33 00 00 00 ... 00

因此,右移 8 位将移出最低 数字。您不需要 shr 指令来执行此操作。只需复制内存:

mov  edi, number
lea  esi, [edi+1]
mov  ecx, 99
cld
rep movsb
mov  [edi], cl           ; CL=0

上面的代码对整个 100 字节的缓冲区做了什么,下面的代码只对前 4 个字节做了什么。

mov  eax, [number]
shr  eax, 8
mov  [number], eax

shr  dword [number], 8

如果我们将 100 字节的 数字 视为位串,我们可以将其内容向下移动 8 以外的计数:

    mov  ebx, number
    mov  eax, [ebx]
More:
    mov  edx, [ebx+4]
    shrd eax, edx,  4        ; Shift count [0-31]
    mov  [ebx], eax
    add  ebx, 4
    mov  eax, edx
    cmp  ebx, number+96
    jb   More
    shr  eax,  4             ; Shift count [0-31]
    mov  [ebx], eax

【讨论】:

  • 我基于带有section .bss 的 YASM 的猜测是,这至少是 32 位代码,并且字节和 dword 之间似乎存在混淆,所以再次使用 32 位代码自然大小是有道理的。并不是说你不能在 32 位模式下使用 rep movsb,而是我很惊讶看到 16 位地址。
  • 另外,mov cl,4?您已经在使用 32 位寄存器和 shrd(386 或更高版本),并且立即移位是 186 中的新功能。变量计数 shrd 在当前主流 Intel CPU 上比立即移位慢。 (还有shr,但没那么糟糕。)我猜你是在说明这是一个变量输入。
  • 我还提到shr dword [number], 8 相当于加载/移位/存储序列。
  • @PeterCordes 我打算将其视为 32 位代码,但我想旧习惯不会消失。在我的答案初稿中,我使用了立即班次计数,但我觉得它不够突出。现在正在编辑...
猜你喜欢
  • 2017-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-20
  • 2021-12-27
  • 2012-06-27
  • 1970-01-01
相关资源
最近更新 更多