在程序集x86中...运行时ECX保持奇数(循环)时出错

时间:2016-08-21 22:42:26

标签: assembly x86

这个程序适用于x86中的反向数组(交换),但当元素数为奇数时它有runTime Error

.data
arr dword 9 dup (1) ; if elements=10 no problem ..!!

.code

main proc
    mov ecx, (lengthof arr )
    mov esi,0
    mov edi,(lengthof arr-1) * type arr
lp:
    mov eax , arr[esi]
    xchg eax , arr[edi]
    mov arr[esi] ,eax
    add esi, type arr
    sub edi, type arr
    dec ecx
    loop lp

    retn
main endp

end main

1 个答案:

答案 0 :(得分:0)

loop already decrements ecx,因此您遇到与Issue With Using dec to Create a Delay相同的问题。

dec   ecx
loop  lp

相同
dec   ecx
dec   ecx
jnz   lp

sub   ecx, 2
jnz   lp

如果计数器从奇数开始,它从1变为-1,因此零检验永远不会成立。如果您使用jg进行循环,那么它就会正常运行。因此,您使用esiedi运行您正在循环的数组的末尾。

如果您在调试器中单步执行循环时看到ecx的值发生了变化,那么您很容易看到这一点。 (有关使用gdb for asm的提示,请参阅标记wiki的底部。

代码审核:

除非您需要原子读取 - 修改 - 写入功能(隐式xchg前缀),否则不要将lock与内存一起使用,因为它 比仅使用单独加载/存储。

您还会破解调用者的esiedi值,这些值在大多数ABI中都会被保留。

该怎么做:

不要将ecx用作循环计数器,因为您已经使用esi和edi作为索引。只要cmp / ja他们在彼此通过时就停止循环。 loop指令在大多数情况下是一个糟糕的选择,因为它很慢并且通常你已经在另一个寄存器中有一些作为循环计数器的东西。

e.g。

main proc
    push   esi
    mov    esi, OFFSET arr      ;  not just arr, since this isn't NASM
    lea    ecx, [esi + (lengthof arr-1) * type arr]     ; ecx = pointer to last element
swaploop:
    mov    eax, [esi]           ; need to use different register sizes if type arr isn't 4 bytes
    mov    edx, [ecx]

    mov    [esi], edx           ; store to opposite locations
    mov    [ecx], eax

    add    esi, type arr
    sub    ecx, type arr
    cmp    esi, ecx
    jb     swaploop            ; while(low < high)   // (unsigned compare)

    pop    esi
    ret

请注意mov eax, [esi] / add esi, 4 could be a lodsd instruction,但是您需要为商店地址设置-4位移,而且可能会更慢。