-2

我目前正在尝试习惯汇编程序,并且我已经在 C++ 中编写了一个 for 循环,然后我在反汇编中查看了它。我想知道是否有人可以向我解释每个步骤的作用和/或如何手动改进循环。

for (int i = 0; i < length; i++){
     013A17AE  mov         dword ptr [i],0  
     013A17B5  jmp         encrypt_chars+30h (13A17C0h)  
     013A17B7  mov         eax,dword ptr [i]  
     013A17BA  add         eax,1  
     013A17BD  mov         dword ptr [i],eax  
     013A17C0  mov         eax,dword ptr [i]  
     013A17C3  cmp         eax,dword ptr [length]  
     013A17C6  jge         encrypt_chars+6Bh (13A17FBh)  
temp_char = OChars [i];         // get next char from original string
     013A17C8  mov         eax,dword ptr [i]  
     013A17CB  mov         cl,byte ptr OChars (13AB138h)[eax]  
     013A17D1  mov         byte ptr [temp_char],cl  

提前致谢。

4

4 回答 4

4

首先,我注意到您发布的内容似乎只包含循环体的一部分。其次,看起来你编译时关闭了所有优化——当/如果你打开优化,如果结果看起来完全不同,不要感到惊讶。

也就是说,让我们逐行查看代码:

 013A17AE mov dword ptr [i],0

这基本上只是i=0

 013A17B5 jmp encrypt_chars+30h (13A17C0h)

这将进入循环的开始。尽管在大多数高级语言中将测试置于循环顶部是很常见的,但在汇编语言中并非总是如此。

 013A17B7 mov eax,dword ptr [i]
 013A17BA add eax,1
 013A17BD mov dword ptr [i],eax

这是i++(非常次优的)汇编语言。它正在检索 的当前值i,将其加一,然后将结果存储回i.

 013A17C0 mov eax,dword ptr [i]
 013A17C3 cmp eax,dword ptr [length]
 013A17C6 jge encrypt_chars+6Bh (13A17FBh) 

这基本上if (i==length) /* skip forward to some code you haven't shown */是检索 的值i并将其与 的值进行比较,如果大于或等于length,则跳转到某处。ilength

如果您是用汇编语言手工编写的,您通常会使用xor eax, eax(或sub eax, eax)之类的东西将寄存器归零。在大多数情况下,如果可能,您将从最大值开始倒数到零(避免循环中的比较)。您当然不会将值存储到变量中,然后立即将其取回(公平地说,如果您打开优化,编译器也可能不会这样做)。

应用它,并将“变量”移动到寄存器中,我们最终会得到以下一般顺序的东西:

    mov ecx, length
loop_top:
    ; stuff that wasn't pasted goes here
    dec ecx
    jnz loop_top
于 2012-04-16T22:11:48.183 回答
0

我将尝试用简单的英语解释这一点:

 013A17AE  mov         dword ptr [i],0               ; Move into i, 0
 013A17B5  jmp         encrypt_chars+30h (13A17C0h)  ; Jump to check
 013A17B7  mov         eax,dword ptr [i]             ; Load i into the accumulator (register eax)
 013A17BA  add         eax,1                         ; Increment the accumulator
 013A17BD  mov         dword ptr [i],eax             ; and put that in it, effectively adding
; 1 to i.
check:
 013A17C0  mov         eax,dword ptr [i]             ; Move i into the accumulator
 013A17C3  cmp         eax,dword ptr [length]        ; Compare it to the value in 'length',
; setting flags
 013A17C6  jge         encrypt_chars+6Bh (13A17FBh)  ; Jump if it's greater or equal. This
; address is not in your code snippet

编译器更喜欢 EAX 进行算术运算。每个寄存器(过去,我不知道这是否仍然是最新的)都有某种类型的操作,它执行起来更快。

于 2012-04-16T22:16:11.627 回答
0

这是应该更优化的部分:(
注意:你的编译器应该这样做,所以要么你关闭了优化,要么循环体中的某些东西阻止了这种优化)

mov eax,dword ptr [i]    ; Go get "i" from memory, put it in register EAX
add eax,1                ; Add one to register EAX
mov dword ptr [i],eax    ; Put register EAX back in memory "i". (now one bigger)
mov eax,dword ptr [i]    ; Go get "i" from memory, put it in EAX again.

看看您将值从内存来回移动到 EAX 的频率?

您应该能够在循环开始时将“i”加载到 EAX 中,直接从 EAX 运行整个循环,并在完成后将完成的值放回“i”。(除非您的代码中的其他内容阻止了这一点)

于 2012-04-16T22:16:14.467 回答
0

无论如何,此代码来自 DEBUG 构建。可以对其进行优化,但是 MS 编译器为这种简单的情况生成了非常好的代码。

手动做没有意义,只需在发布模式下重新构建它并阅读清单以了解如何做。

于 2012-04-16T22:23:19.560 回答