【问题标题】:Wrong output due to shl on al and ax in the code NASM 64 bit programming由于代码 NASM 64 位编程中 al 和 ax 上的 shl 导致输出错误
【发布时间】:2018-04-14 19:17:36
【问题描述】:

我编写了一个代码来将两个 8 位十六进制数相乘并应用移位和加法方法。我在名为“a”和“b”的变量中取了两个输入,它们是字节类型,并将它们存储在 al 和 bl 中。

在乘法过程中,al 左移,bl 右移。 稍后,在循环中,我将 ax(a) 添加到 dx 寄存器(初始化为 0)。 但是,问题是当 shl ax,1 被替换为 shl al,1 那么我没有得到所需的输出。即 - a=12 和 b=10 然后只打印 20 而不是 120。

请解释一下,为什么我不能写 shl al,1。

这里是代码

%macro print 2
    mov rax,1
    mov rdi,1
    mov rsi,%1
    mov rdx,%2
    syscall
%endmacro

%macro accept 2
    mov rax,0
    mov rdi,0
    mov rsi,%1
    mov rdx,%2
    syscall
%endmacro

%macro exit 0
    mov rax,60
    mov rdi,0
    syscall
%endmacro

section .data
    a db 12H
    b db 10H
    msg db 10,"Result : ",10
    len equ $-msg
;------------------------
section .bss
    tempbuff resb 16    ;temporary buffer for displaying the ascii

;------------------------

section .text
global _start
_start:
    mov rdx,0
    mov al,byte[a]  ;al is multiplicand
    mov bl,byte[b]  ;bl is multiplier
    mov rcx,8
    lp:
        shr bl,1    
        jnc haha
        add dx,ax
        haha:
            shl ax,1    ;shl al,1 doesn;t work
    loop lp
    mov rbx,0
    mov rbx,rdx
    call hex_ascii      ;converting the hex no into ascii

exit

hex_ascii:
    mov rsi,tempbuff
    mov rcx,16
    mov rax,0
    bah:
        rol rbx,4
        mov al,bl
        and al,0FH
        cmp al,09H
        jbe add30
        add al,07H
        add30:
            add al,30H
        mov [rsi],al
        inc rsi
    loop bah
    print tempbuff,16   
ret

【问题讨论】:

  • 如果您在al 中有一个 8 位值并且您想将其左移然后添加到dx,您需要将ax 左移,否则您会丢失被乘数。换句话说,您希望继续将其左移,保留所有位,并在每次看到乘数中的 1 时将其添加到中间结果中。
  • 但是当我将 al 位左移时,移位的位不会到达 ax 寄存器的 ah 部分。然后我将如何松开它们
  • shl al,1 根本不影响ah。它只影响ah。这就是为什么你需要shl ax,1

标签: assembly nasm x86-64


【解决方案1】:

如果您在al 中有一个 8 位值并且您想将其左移然后添加到dx,您需要将ax 左移,否则您会丢失被乘数的位。换句话说,您希望继续将其左移,保留所有位,并在每次看到乘数中的 1 时添加到中间结果。

shl al,1 完全不影响ah。它只影响ah。这就是您需要shl ax,1 的原因。由于shl al,1 轮班

这是一个例子。最初:

al = 01011001
ax = 0000000001011001
bl = 00010111
dx = 0000000000000000

右移bl 得到一个1 位,左移al。我们有一个来自bl 移位的1 位,所以将ax 添加到dx

al = 10110010
ax = 0000000010110010
bl = 00001011
dx = 0000000010110010

右移bl 得到一个1 位,左移al。我们有一个来自bl 移位的1 位,所以将ax 添加到dx

al = 01100100
ax = 0000000001100100  <-- wrong! result of shifting al
bl = 00000101
dx = 0000000100010110  <-- wrong because ax was wrong

呃哦,麻烦了。 ax 现在错了。我们丢失了al 左移的位。

这就是我们想要的:

al = 01100100
ax = 0000000101100100  <-- This is what we want, result of shifting ax
bl = 00000101
dx = 0000001000010110  <-- This is what we want, from correct ax

如果您查看documentation for shl,您会发现al 的高位在shl al,1 指令中被移入CF(进位标志)。然后,如果您希望使用“通过进位旋转”,您可以将该位旋转到 ah

shl al,1
rcl ah,1

但是你可以使用一条指令得到你想要的结果:

shl ax,1

【讨论】:

  • 有趣的事实:你也可以adc ah,ah 代替rcl ah,1。现有位左移 1(因为这就是 add same,same 所做的),然后 CF 被添加并成为低位。事实上,如果您只使用 8 位寄存器add al,al / adc ah,ah 可能是现代 CPU 的最佳实现。 (比 RCL 更好的吞吐量)。但当然shl ax,1 或更好的add ax,ax 是迄今为止最好的。或者实际上是 add eax,eax 对于 x86-64。 shladd 之间的唯一区别是 CF 和 ZF 以外的一些标志的设置方式,以及在更多端口上运行的方式。
  • @PeterCordes 是的,确实如此。我更专注于回答 OP 的问题,即为什么简单的 shl al,1 不起作用但 shl ax,1 起作用,而且我对其他可能的选择变得懒惰。不知道为什么旋转式随身携带首先出现在我的脑海中。
  • shlrcl 更好地说明了像 OP 一样执行此操作(没有引入添加等效于移位的概念,或者通过像实际编译器 godbolt.org/g/TbczcT 那样进行优化),我的评论不是对您的答案的建议改进,只是一个有趣的事实/相关阅读。
猜你喜欢
  • 1970-01-01
  • 2018-12-26
  • 2019-12-28
  • 1970-01-01
  • 1970-01-01
  • 2015-01-25
  • 1970-01-01
  • 1970-01-01
  • 2017-06-09
相关资源
最近更新 更多