【发布时间】:2020-09-13 07:32:39
【问题描述】:
对于上下文:由于在线课程,一些印度大学的计算机课程已经减少为老师,他们只是给我们代码并期望我们死记硬背。
程序是计算给定数组中 +ve 和 -ve 数字的数量。 The entire code is here.
我的问题是从第 45 行到第 59 行(如下所示)
mov esi, arr
mov ecx,arr_size ;Array counter i.e. 6
mov ebx,0; ;counter for +ve nos
mov edx,0; ;counter for -ve nos.
next_num:
mov eax,[esi] ; take no. in RAX
rcl eax,1 ; rotate left 1 bit to check for sign bit
jc negative
positive:
inc ebx ; no carry, so no. is +ve
jmp next
negative:
inc edx ; carry, so no. is -ve
next:
add esi,4 ; 32 bit nos i.e. 4 bytes
loop next_num
在上面的代码中,据我所知,我将数组的起始位置存储在 ESI 寄存器中并扫描每个元素并检查它是否为正
但是,我如何知道何时到达数组的末尾?
代码正在维护 ECX 寄存器,但不使用它。那为什么不是无限运行呢?
难道不应该有某种带有 DEC ECX 和 JE 0 指令的循环吗?
【问题讨论】:
-
loop next_num指令大致等价于dec ecx; jnz next_num。 -
一个好的开始是在调试器中单步执行它以观察寄存器值的变化。然后,如果
loop更改了 ECX 让您感到惊讶,请查看指令集参考手册。 -
另外,这是一种测试符号位的低效方法。如果
EAX < 0(有符号比较),test eax,eax/jl negative将是跳转的惯用方式。jl条件基于符号标志,无需将其轮换为进位。你甚至可以cmp dword [esi], 0来比较一个内存操作数。另请注意,非负数包括零,这也不是正数。此外,无需更新循环内的两个计数器,只需用shr eax, 31/add ebx, eax计算负数,最后计算non_neg = total - negative。不需要分支,直接将符号位相加。 -
@Peter Cordes:在
test eax, eax之后,您还可以使用js negative,我觉得这比使用jl更清晰。 -
@ecm:是的,符号位本身存在分支的语义含义,而在小于零的值上存在分支。 (
jl的语义含义更适合cmp eax, 0;针对自身测试寄存器是cmp0 的窥视孔优化,因此 test/jl 需要仔细考虑该含义以使其看起来自然。有趣的事实:cmp reg,0/js将是 slower on Core 2,可以将 cmp 与jl进行宏融合,但不能将js融合。即使 Core 2 也可以融合test/js,所以任何一个成语都可以)
标签: assembly x86 nasm microprocessors