我目前正在尝试习惯汇编程序,我在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
提前致谢。
答案 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编译器为这种简单的情况生成了非常好的代码。
没有必要手动完成,只需在发布模式下重新构建它并阅读列表以了解如何操作。