为什么逻辑向左移动&或装配中的某些值

时间:2017-10-21 14:08:52

标签: assembly masm32

我目前正在大学学习装配,并且最近开始编写装配程序,以便在32x32 LED模拟器上点亮LED。

我们本周有一个实验室,第一个问题是"创建一个程序,点亮一个随机的单个LED并继续,直到所有的LED都点亮"。我有一个朋友告诉我他们是如何做到的但我仍然对一些选项如何运作感到困惑。 下面是代码:

.data
x           DWORD   0
y           DWORD   0
row         DWORD   0
row_copy    DWORD   00000001h

.code
    main:nop

        invoke version
        invoke setPattern, 0
    row_random:
        invoke random, 32 ;create a random number between 0-31
        mov x, eax        ;move that value into memory location x
        invoke readRow, x ;select a row to be altered 
        mov row, eax 
    row_on:
        invoke random, 32
        mov ecx, eax      ;move the random value into ecx
        shl row_copy, CL  ;shift left with carry flag (This is where Im confused)
        mov eax, row
        mov ebx, row_copy
        or eax, ebx ; I'm also unsure as to why this is happening 
        invoke writeRow, x, eax  ;alter a pixel at the random row x with the value of eax
        mov row_copy, 00000001h
        ;invoke Sleep, 1
        jmp row_random
        invoke ExitProcess,0

最初当我这样做时,我创建了一个0到31之间的随机数,在EBX中设置它,并使用writeRow和x和ebx。不过那是错的。有人可以向我解释为什么你在逻辑上向左转CL吗?为什么它必要或两个值?我认为或者是否确保你不会在LED已经打开的情况下意外关闭它?

1 个答案:

答案 0 :(得分:1)

CL是ecx的低字节。你把它与CF(EFLAGS中的进位标志)混淆了。 x86 variable-count shift instructions require the shift-count to be in cl

只是为了记录,该代码搞笑效率低下。 row_copy使用内存目标指令(慢)移动,然后加载,然后再次用1替换!所以......你本可以做到的

mov    ecx, eax
mov    ebx, 1
shl    ebx, cl
像普通人一样。根本没有理由为row_copy设置内存位置,只需在寄存器中执行即可。当寄存器用完时,你只需要静态存储器。

代码实现的基本逻辑是row |= (1 << rand_0_31)来设置一个随机位(可能已经设置好了)。

如果您想了解此代码的运作方式,请在调试器中单步调试并观察寄存器中的值更改。另请参阅标记wiki以获取指南,文档和调试技巧。

BTW,创建一个1位掩码的更有效方法是xor ebx,ebx / bts ebx, eax,以避免在ECX中需要移位计数,但如果你还没有学过BTS,它没有做任何你不能用其他简单指令做的事情。

实际上,BTS意味着您根本不需要单独的掩码和OR指令,只需在一个寄存器中获取该行的旧值,在另一个寄存器中获取一个随机数,然后bts ebx, eax在EBX中设置EAX位。

假设您的函数调用约定只包含ECX和EDX(加上带返回值的EAX),则不需要任何静态存储位置,只需注册即可。我会做类似的事情:

; untested
.code
    main:
        push  ebx   ; save a couple call-preserved registers
        push  edi   ; for values that survive across function calls

        ; nop       ; what's the point of this NOP?
        invoke version
        invoke setPattern, 0

    row_random:
        invoke random, 32 ;create a random number between 0-31
        mov    ebx, eax         ; eax = ebx = row
        invoke readRow, eax
        mov    edi, eax         ; edi = old value of row
        invoke random, 32

        mov    ecx, eax         ; ecx = random column = bit position
        mov    eax, 1
        shl    eax, cl          ; 1 << random
        or     edi, eax         ; row_value |= 1<<random

        invoke writeRow, ebx, edi  ; pixel[ebx] |= 1<<random

        jmp row_random
        ; or loop a finite number of times with dec / jnz.

        pop  edi
        pop  ebx
        return
        ;  invoke ExitProcess,0

整个中间块(带有shl和or)可以是bts edi, eax

invoke是一个宏,可能会在call之后推送并清理堆栈,因此通过使用mov存储到堆栈并将空间留在那里可以提高效率。此外,如果您使用足够新的CPU,则可以使用rdrand ebx来获得乐趣。

有趣的事实:移位指令会掩盖计数,因此无论您使用什么输入,它们总是移位0-31,因此在and ecx, 31之后您不需要RDRAND ECX位位置。< / p>

此外,您可以调用random 32*32并将结果拆分为行位和列位。