【发布时间】:2017-05-25 14:08:41
【问题描述】:
我正在尝试在汇编中翻译 C++ 递归代码。我在 32 位模式下工作。
这是 C++ 代码。
1 extern "C" void output (unsigned);
2 extern "C" void parcours (unsigned[], unsigned, unsigned = 0);
3
4 void parcours (unsigned v[], unsigned n, unsigned k) {
5 while (k < n) {
6 output(v[k]);
7 parcours(v, n, 2*k+1);
8 k = 2*k+2;
9 }
10 }
这是我翻译它的尝试。我正在努力将递归 C++(或任何其他高级语言)翻译成汇编。如果您能更正此代码并指出我的错误,我将不胜感激。
%include "io.inc"
section .text
global start
start:
mov edi, [ebp+8] ;address of the first element of the array
mov eax, [ebp+12] ;n
mov edx, [ebp+16] ;k
parcours:
enter 0,0 ;stack frame creation
push edx ;we save k before the modification
shl edx,1
add edx,1 ;2*k+1
loop:
cmp edx,eax
jb endloop ;if k < n
push [edi+edx] ;we push for the output
call output
pop ebx
call parcours
shl edx,1 ;2*k
add edx,2 ;2*k+2
jmp loop
endloop:
pop edx
leave ;stack frame destruction
ret
【问题讨论】:
-
将非递归和递归 C++ 转换为程序集没有区别,从 CPU 的角度来看,实际上很难在每个可能的源中可靠地检测递归性,也不会影响生成的程序集以任何方式。编译器将按照配置的调用约定将其编译为任何其他函数。您可以使用 C++ 编译器来检查编译器会做什么(但设置合理的优化量以获得一些不错的程序集可能会很棘手)。您当前的程序集可能会使寄存器中的值杂乱无章,应该保留这些值。
-
实际上,您不会将
ebx用于任何事情,只是作为草稿,但如果我猜对了您的调用约定,您应该保存它(或避免完全弄乱它)。而eax, edx可能无法生存call output。否则,该代码对我来说看起来相当不错,请在调试器中尝试以查看自己,如果它按预期工作(使用一些仅执行无递归的参数,然后 depth=1,然后 depth=2+)。 -
只需遵循编译器调用约定,它就可以工作,没有理由设计递归与非递归,它们可以是相同的代码。
-
重点是我想锻炼自己并正确理解它是如何工作的。 @Ped7g 我会试试你说的。
-
enter 0,0- 好的,但我建议push ebp \ mov ebp, esp(如果编译器使用帧指针,你也会看到编译器这样做)