为什么逻辑左移&或汇编中的某些值
Why logic shift left & or certain values in assembly
我目前正在大学学习汇编,最近开始编写汇编程序来点亮 32x32 LED 模拟器上的 LED。
我们这周有一个实验室,第一个问题是 "create a program that lights up a random individual LED and continues until all LED's are lit"。我有一个朋友向我展示了他们是如何做到的,但我仍然对某些选项的工作原理感到困惑。
代码如下:
.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 关闭?
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)
设置一个随机位(可能已经设置)。
如果您想查看此代码的运行方式,请在调试器中单步执行它并观察寄存器中值的变化。另请参阅 x86 标签 wiki 了解指南、文档和调试提示。
顺便说一句,一种更有效的创建 1 位设置掩码的方法是 xor ebx,ebx
/ bts ebx, eax
以避免在 ECX 中需要移位计数,但是如果你还没有了解 BTS然而,它不会执行其他更简单的指令无法执行的任何操作。
实际上,BTS 意味着您根本不需要单独的掩码和 OR 指令,只需在一个寄存器中获取行的旧值,在另一个寄存器中获取随机数,然后 bts ebx, eax
设置 EBX 中的第 EAX 位。
假设您的函数调用约定仅破坏 ECX 和 EDX(加上具有 return 值的 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
存储到堆栈并将space 那里。此外,如果您使用的是足够新的 CPU,您可以使用 rdrand ebx
来获得乐趣。
有趣的事实:移位指令屏蔽了计数,因此无论您使用什么输入,它们总是移位 0-31,因此您不需要在 RDRAND ECX
之后的 and ecx, 31
作为位位置.
此外,您可以调用 random 32*32
并将结果拆分为行位和列位。
我目前正在大学学习汇编,最近开始编写汇编程序来点亮 32x32 LED 模拟器上的 LED。
我们这周有一个实验室,第一个问题是 "create a program that lights up a random individual LED and continues until all LED's are lit"。我有一个朋友向我展示了他们是如何做到的,但我仍然对某些选项的工作原理感到困惑。 代码如下:
.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 关闭?
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)
设置一个随机位(可能已经设置)。
如果您想查看此代码的运行方式,请在调试器中单步执行它并观察寄存器中值的变化。另请参阅 x86 标签 wiki 了解指南、文档和调试提示。
顺便说一句,一种更有效的创建 1 位设置掩码的方法是 xor ebx,ebx
/ bts ebx, eax
以避免在 ECX 中需要移位计数,但是如果你还没有了解 BTS然而,它不会执行其他更简单的指令无法执行的任何操作。
实际上,BTS 意味着您根本不需要单独的掩码和 OR 指令,只需在一个寄存器中获取行的旧值,在另一个寄存器中获取随机数,然后 bts ebx, eax
设置 EBX 中的第 EAX 位。
假设您的函数调用约定仅破坏 ECX 和 EDX(加上具有 return 值的 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
存储到堆栈并将space 那里。此外,如果您使用的是足够新的 CPU,您可以使用 rdrand ebx
来获得乐趣。
有趣的事实:移位指令屏蔽了计数,因此无论您使用什么输入,它们总是移位 0-31,因此您不需要在 RDRAND ECX
之后的 and ecx, 31
作为位位置.
此外,您可以调用 random 32*32
并将结果拆分为行位和列位。