【问题标题】:How can I do a bit shift for a large sequence of bytes in NASM Assembly?如何在 NASM 汇编中对大量字节序列进行位移?
【发布时间】:2013-11-24 13:01:10
【问题描述】:

假设我在.data中定义了X个字节数:

db 00000000b,00100011b,11100011b,...........

假设我定义了 50 个字节。

我想获取这 50 个字节,然后向左移动一个大位移位。上面的示例将如下所示:

db 00000000b,01000111b,11000110b,...........

当我们使用 4 个字节时,这很容易做到,因为您只需将它们放入 EAX 并进行转换。但现在我有 50 个字节。

我怎样才能做到这一点?

【问题讨论】:

  • 移位多少?您需要不同的算法来移位 1、小于 8 以及 8 或更多。
  • @SevaAlekseyev:小于 8(在本例中为 1)。

标签: assembly x86 nasm


【解决方案1】:

如果只进行一位左移,您可以使用 rcl 指令将一个内存字左移一位,捕获进位,并在下一个字上重复。您想为第一次迭代重置进位。 (我很确定这不是 NASM 语法,但这应该不会打扰你)。

   mov   esi, offset data_buffer
   mov   ebx, data_buffer_dword_count
   lea   esi, [esi+4*ebx-4]
   clc
loop:
   rcl   [esi]
   lea   esi, -4[esi]
   dec   ebx             ; this kind of loop is why dec instructions don't affect carry!
   jne   loop

如果移动 N>1 位,这很慢。在这种情况下,请使用 shift-left-double 指令。该指令使用两个寄存器,并将这对移位指定的距离(cl 或某个立即数)。您需要跟踪部分偏移的结果;记账有点棘手。

如果您的移位距离为 31 位或更少,则应使用以下代码: (编辑:我用不那么笨拙的东西替换了以前的代码):

   mov   esi, offset data_buffer
   mov   ebx, data_buffer_dword_count
   lea   esi, [esi+4*ebx-4]
   xor   edi, edi        ; bits from last time; this acts like "clc" in above loop
loop:
   mov   eax, [esi]
   xor   edx, edx        ; make 64 bit value of next dword
   mov   ecx, shift_left_distance
   shld  edx, eax, cl    ; shift left across <edx,eax>
   add   eax, edi        ; form full shifted dword by combining with last partial 
   mov   [esi], eax      ; update storage with shifted result
   mov   edi, edx        ; save shifted but unstored bits from this round
   lea   esi, -4[esi]
   dec   ebx
   jne   loop

如果你想移动超过 31 位,那么你可以结合使用内存偏移量(dwords 中的移动距离除以 32)来混洗 dwords 的想法与上述移动距离模 32 的方案。

【讨论】:

  • or 不是 add 组合位的更好选择吗?
  • 这有关系吗?目标位为零。
  • 我是老派。我从一台有 ADD 和 AND 但没有 OR 的机器开始。旧习惯很难改掉:-}
  • 我从Z80开始,旧时代的豪车:)
  • 如果您想看看旧时代的 Edsel,请查看 PDP-8。
【解决方案2】:

将字节数组左移一位最好使用 add + adc 序列来实现——您可以组合任意长度的操作,例如:

lea edi, [array]
mov eax, [edi]
mov bx,  [edi + 4]
mov cl,  [edi + 6]

add eax, eax        ;; shift the MSB to Carry bit
adc bx, bx          ;; shift the previous carry to bit 0 + produce new carry
adc cl, cl

mov [edi], eax      ;; write back
mov [edi + 4], bx
mov [edi + 6], cl

【讨论】:

    【解决方案3】:

    通常有一种移位方式,即移入或通过进位位。进位位用于从一个移位操作中取出移位,并使用它在下一个移位操作中移入。因此,如果向左移动,您将从 lsbyte 开始,它的 msbit 移出,然后移入 lsbyte 的下一个右侧,依此类推,在所有字节上产生级联效应。我将把它留给读者查找移位操作,看看哪些是做什么的。请记住您需要控制移位的第一个移位操作,因此清除进位位或使用不同的指令。通常通过进位进行的移位称为旋转。

    【讨论】:

      【解决方案4】:

      将任意数量的字节左移一位:首先SHL 最低有效字节一位。然后RCL 所有其他字节一位,从第二个最低有效位到最高有效位。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多