我有两个函数,它们从输入读取整数x和y。
产品返回x * y
power返回x ^ y,但是它使用递归和乘积来计算它。所以x将是“base”而y是“exponent”。
他们从C ++打来电话:
int a, b, x, y;
a = product(x, y);
b = power(x, y);
这是asm。我得到了产品,但是我遇到了电源问题,因为我不确定从它调用产品的语法/方法/约定(并且自己调用递归)。编辑:必须使用递归。
global product
global power
section .text
product:
push ebp
mov ebp, esp
sub esp, 4
push edi
push esi
xor eax, eax
mov edi, [ebp+8]
mov esi, [ebp+12]
mov [ebp-4], edi
product_loop:
add [ebp-4], edi
mov eax, [ebp-4]
sub esi, 1
cmp esi, 1
jne product_loop
product_done:
pop esi
pop edi
mov esp, ebp
pop ebp
ret
power:
push ebp
mov ebp, esp
sub esp, 4
push edi
push esi
push ebx
xor eax, eax
mov edi, [ebp+8]
mov esi, [ebp+12]
;;;
check:
cmp esi, 1 ; if exp < 1
jl power_stop
recursion: ; else (PLEASE HELP!!!!!!!!)
; eax = call product (base, (power(base, exp-1))
power_stop:
mov eax, 1 ; return 1
power_done:
push ebx
pop esi
pop edi
mov esp, ebp
pop ebp
ret
编辑:我的解决方案!
power:
; Standard prologue
push ebp ; Save the old base pointer
mov ebp, esp ; Set new value of the base pointer
sub esp, 4 ; make room for 1 local variable result
push ebx ; this is exp-1
xor eax, eax ; Place zero in EAX. We will keep a running sum
mov eax, [ebp+12] ; exp
mov ebx, [ebp+8] ; base
cmp eax, 1 ; n >= 1
jge L1 ; if not, go do a recursive call
mov eax, 1 ; otherwise return 1
jmp L2
L1:
dec eax ; exp-1
push eax ; push argument 2: exp-1
push ebx ; push argument 1: base
call power ; do the call, result goes in eax: power(base, exp-1)
add esp, 8 ; get rid of arguments
push eax ; push argument 2: power(base, exponent-1)
push ebx ; push argument 1: base
call product ; product(base, power(base, exponent-1))
L2:
; Standard epilogue
pop ebx ; restore register
mov esp, ebp ; deallocate local variables
pop ebp ; Restore the callers base pointer.
ret ; Return to the caller.
答案 0 :(得分:2)
您正在使用CDECL调用约定,因此您必须先向后推送堆栈中的参数,然后调用该函数,然后在返回后清理堆栈。
push arg_last
push arg_first
call MyFunction
add esp, 8 ; the argument_count*argument_size
但是这里有一些关于你的代码的注释:
您的函数product
不会返回任何值。在mov eax, [ebp-4]
标签后立即使用product_done
。
指令mul
或imul
很容易实现乘法。使用添加是最慢的方式。
通过递归计算功率不是最好的主意。使用以下算法:
Y = 1;
如果N = 0退出。
如果N是奇数 - > Y = Y * x; N = N-1
如果N是偶数 - > Y = Y * Y; N = N / 2
转到2
使用SHR
指令将N除以2.使用test
指示检查奇数/偶数。
这样,您无需从product
函数调用power
。
答案 1 :(得分:1)
如果您不确定如何编写程序集,通常可以用C ++编写它并将其组装成线索 - 例如:
int power(int n, int exp)
{
return exp == 0 ? 1 :
exp == 1 ? n :
product(n, power(n, exp - 1));
}
然后您应该只能使用gcc -S
或编译器等效开关用于汇编输出,或者如果您愿意,可以反汇编机器代码。
例如,使用Microsoft的编译器ala int product(int x, int y) { return x * y; }
编译的int main() { return product(3, 4); }
和cl /Fa power.cc
中抛出的上述函数:
; Listing generated by Microsoft (R) Optimizing Compiler Version 15.00.30729.01
TITLE C:\home\anthony\user\dev\power.cc
.686P
.XMM
include listing.inc
.model flat
INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES
PUBLIC ?product@@YAHHH@Z ; product
; Function compile flags: /Odtp
_TEXT SEGMENT
_x$ = 8 ; size = 4
_y$ = 12 ; size = 4
?product@@YAHHH@Z PROC ; product
; File c:\home\anthony\user\dev\power.cc
; Line 1
push ebp
mov ebp, esp
mov eax, DWORD PTR _x$[ebp]
imul eax, DWORD PTR _y$[ebp]
pop ebp
ret 0
?product@@YAHHH@Z ENDP ; product
_TEXT ENDS
PUBLIC ?power@@YAHHH@Z ; power
; Function compile flags: /Odtp
_TEXT SEGMENT
tv73 = -8 ; size = 4
tv74 = -4 ; size = 4
_n$ = 8 ; size = 4
_exp$ = 12 ; size = 4
?power@@YAHHH@Z PROC ; power
; Line 4
push ebp
mov ebp, esp
sub esp, 8
; Line 7
cmp DWORD PTR _exp$[ebp], 0
jne SHORT $LN5@power
mov DWORD PTR tv74[ebp], 1
jmp SHORT $LN6@power
$LN5@power:
cmp DWORD PTR _exp$[ebp], 1
jne SHORT $LN3@power
mov eax, DWORD PTR _n$[ebp]
mov DWORD PTR tv73[ebp], eax
jmp SHORT $LN4@power
$LN3@power:
mov ecx, DWORD PTR _exp$[ebp]
sub ecx, 1
push ecx
mov edx, DWORD PTR _n$[ebp]
push edx
call ?power@@YAHHH@Z ; power
add esp, 8
push eax
mov eax, DWORD PTR _n$[ebp]
push eax
call ?product@@YAHHH@Z ; product
add esp, 8
mov DWORD PTR tv73[ebp], eax
$LN4@power:
mov ecx, DWORD PTR tv73[ebp]
mov DWORD PTR tv74[ebp], ecx
$LN6@power:
mov eax, DWORD PTR tv74[ebp]
; Line 8
mov esp, ebp
pop ebp
ret 0
?power@@YAHHH@Z ENDP ; power
_TEXT ENDS
PUBLIC _main
; Function compile flags: /Odtp
_TEXT SEGMENT
_main PROC
; Line 11
push ebp
mov ebp, esp
; Line 12
push 4
push 3
call ?power@@YAHHH@Z ; power
add esp, 8
; Line 13
pop ebp
ret 0
_main ENDP
_TEXT ENDS
END
向您介绍:
?power@@YAHHH@Z PROC ; power
; Line 4
push ebp
mov ebp, esp
sub esp, 8
以上是power函数的入口代码 - 只需调整堆栈指针跳过函数参数,它将在_exp$[ebp]
(即exp
)和{{1}下面访问}(即_n$[ebp]
)。
n
基本上,如果; Line 7
cmp DWORD PTR _exp$[ebp], 0
jne SHORT $LN5@power
mov DWORD PTR tv74[ebp], 1
jmp SHORT $LN6@power
不等于0,我们将继续在下面的标签exp
,但如果它是0,则将$LN5@power
加载到堆栈上的返回值位置1
并跳转到tv74[ebp]
处的函数返回说明。
$LN6@power
与上面类似 - 如果exp为1,则将n放入eax并从中放入返回值堆栈内存,然后跳转到返回指令。
现在它开始变得有趣......
$LN5@power:
cmp DWORD PTR _exp$[ebp], 1
jne SHORT $LN3@power
mov eax, DWORD PTR _n$[ebp]
mov DWORD PTR tv73[ebp], eax
jmp SHORT $LN4@power
从exp减去1并推入堆栈......
$LN3@power:
mov ecx, DWORD PTR _exp$[ebp]
sub ecx, 1
push ecx
同时将n推入堆栈......
mov edx, DWORD PTR _n$[ebp]
push edx
递归调用幂函数,该函数将使用上面的两个值。
call ?power@@YAHHH@Z ; power
上述函数返回后的堆栈调整。
add esp, 8
将递归调用的结果 - 电源返回指令留在eax寄存器中 - 放到堆栈中......
push eax
同时将n推入堆栈......
mov eax, DWORD PTR _n$[ebp]
push eax
将产品功能调用为多个 call ?product@@YAHHH@Z ; product
上方power
调用返回的值。
n
将 add esp, 8
mov DWORD PTR tv73[ebp], eax
的结果复制到堆栈上的临时地址....
product
从该tv73临时位置获取值并将其复制到tv74 ...
$LN4@power:
mov ecx, DWORD PTR tv73[ebp]
mov DWORD PTR tv74[ebp], ecx
最后,将$LN6@power:
mov eax, DWORD PTR tv74[ebp]
结果从tv74移到eax寄存器中,以便在product()
调用返回后方便快捷地访问。
product
清理堆栈并返回。