对于装配中的循环有效

时间:2012-04-16 22:03:14

标签: c++ visual-studio visual-c++ assembly for-loop

我目前正在尝试习惯汇编程序,我在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 个答案:

答案 0 :(得分: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的值进行比较,如果i大于或等于{,则跳转到某处{1}}。

如果您是手动使用汇编语言编写此函数,通常会使用length(或xor eax, eax)之类的函数来归零寄存器。在大多数情况下,如果可能,您将从最大值开始并向下计数到零(避免在循环中进行比较)。您当然不会将值存储到变量中,然后立即将其检索回来(公平地说,如果启用优化,编译器可能也不会这样做。)

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

sub eax, eax

答案 1 :(得分: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进行算术运算。每个寄存器(过去,我不知道这是否仍然是最新的)具有某种类型的操作,它可以更快地完成。

答案 2 :(得分: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”。 (除非代码中的其他内容阻止了这一点)

答案 3 :(得分:0)

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

没有必要手动完成,只需在发布模式下重新构建它并阅读列表以了解如何操作。