Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何使用传入当前子例程的参数调用不同的子例程(用于递归)?_C++_Assembly_Recursion_X86 - Fatal编程技术网

C++ 如何使用传入当前子例程的参数调用不同的子例程(用于递归)?

C++ 如何使用传入当前子例程的参数调用不同的子例程(用于递归)?,c++,assembly,recursion,x86,C++,Assembly,Recursion,X86,我有两个函数,从输入读取整数x和y 产品返回x*y power返回x^y,但它使用递归和乘积来计算。所以x是“基”,y是“指数” 他们从C++调用: int a, b, x, y; a = product(x, y); b = power(x, y); 这是asm。我让产品正常工作了,但是我在power方面遇到了麻烦,因为我不确定从它调用产品(并为递归调用自身)的语法/方法/约定。编辑:必须使用递归 global product global power secti

我有两个函数,从输入读取整数x和y

产品返回x*y

power返回x^y,但它使用递归和乘积来计算。所以x是“基”,y是“指数”

他们从C++调用:

int a, b, x, y; 
a = product(x, y);
b = power(x, y);
这是asm。我让产品正常工作了,但是我在power方面遇到了麻烦,因为我不确定从它调用产品(并为递归调用自身)的语法/方法/约定。编辑:必须使用递归

    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     
您使用的是调用约定,因此必须首先向后推堆栈中的参数,然后调用函数,然后在返回后清理堆栈

         push   arg_last
         push   arg_first
         call   MyFunction
         add    esp, 8      ; the argument_count*argument_size
但这里有一些关于代码的注释:

  • 您的函数
    产品
    不返回任何值。在
    产品完成后立即使用
    mov eax,[ebp-4]

  • 通过指令
    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
    指令检查奇数/偶数


    这样,您就不需要从<代码> POWER < /COD>函数> <代码/> > > < P> > P >如果您不确定如何编写程序集,您可以一般用C++编写并将其组装成线索-类似于:

    int power(int n, int exp)
    {
        return exp == 0 ? 1 :
               exp == 1 ? n :
               product(n, power(n, exp - 1));
    }
    
    然后,您应该能够使用
    gcc-S
    或编译器用于汇编输出的等效开关,或者如果愿意,可以反汇编机器代码

    例如,上面的函数与
    int-product(int-x,int-y){return x*y;}
    int-main(){return-product(3,4);}
    一起抛出,使用Microsoft编译器ala
    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
    
    上面是幂函数的输入代码-只需调整堆栈指针以跳过函数参数,它将在下面作为
    \u exp$[ebp]
    (即
    exp
    )和
    \u n$[ebp]
    (即
    n
    )访问函数参数

    基本上,如果
    exp
    不等于0,我们将继续标签
    $LN5@power
    如下,但如果为0,则将
    1
    加载到堆栈上
    tv74[ebp]
    处的返回值位置,并跳转到
    $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
    
    与上面类似-如果exp为1,则将n放入eax,并从中放入返回值堆栈内存,然后跳转到返回指令

    现在它开始变得有趣

    $LN3@power:
            mov     ecx, DWORD PTR _exp$[ebp]
            sub     ecx, 1
            push    ecx
    
    从exp中减去1并将其推入堆栈

            mov     edx, DWORD PTR _n$[ebp]
            push    edx
    
            call    ?power@@YAHHH@Z                         ; power
    
            mov     eax, DWORD PTR _n$[ebp]
            push    eax
    
            call    ?product@@YAHHH@Z                       ; product
    
    同时将n推到堆栈上

            mov     edx, DWORD PTR _n$[ebp]
            push    edx
    
            call    ?power@@YAHHH@Z                         ; power
    
            mov     eax, DWORD PTR _n$[ebp]
            push    eax
    
            call    ?product@@YAHHH@Z                       ; product
    
    递归调用幂函数,该函数将使用上面的两个值

            add     esp, 8
    
    在上述函数返回后进行堆栈调整

            push    eax
    
    将递归调用的结果(电源返回指令留在eax寄存器中)放入堆栈

            mov     edx, DWORD PTR _n$[ebp]
            push    edx
    
            call    ?power@@YAHHH@Z                         ; power
    
            mov     eax, DWORD PTR _n$[ebp]
            push    eax
    
            call    ?product@@YAHHH@Z                       ; product
    
    同时将n推到堆栈上

            mov     edx, DWORD PTR _n$[ebp]
            push    edx
    
            call    ?power@@YAHHH@Z                         ; power
    
            mov     eax, DWORD PTR _n$[ebp]
            push    eax
    
            call    ?product@@YAHHH@Z                       ; product
    
    调用product函数,将调用上面的
    power
    返回的值乘以
    n

    ; Line 7
            cmp     DWORD PTR _exp$[ebp], 0
            jne     SHORT $LN5@power
            mov     DWORD PTR tv74[ebp], 1
            jmp     SHORT $LN6@power
    
            add     esp, 8
            mov     DWORD PTR tv73[ebp], eax
    
    产品的结果
    复制到堆栈上的临时地址

    $LN4@power:
            mov     ecx, DWORD PTR tv73[ebp]
            mov     DWORD PTR tv74[ebp], ecx
    
    从tv73临时位置获取值并将其复制到tv74

    $LN6@power:
            mov     eax, DWORD PTR tv74[ebp]
    
    最后,将
    product()
    结果从tv74移动到eax寄存器中,以便在
    product
    调用返回后方便快捷地访问

    ; Line 8
            mov     esp, ebp
            pop     ebp
            ret     0
    

    清理堆栈并返回。

    1st:这里没有使用递归。这只是一个练习吗?编译器生成的代码将比这更快…是的,这只是一个练习@阿图尔:也许是这样,但我正在努力!我不知道怎么做。只需将
    参数推送到堆栈上,然后
    调用
    产品子例程即可。返回值也将在堆栈上(
    pop
    it after
    call
    )。也就是说…为什么要递归?您使用的是循环,它不是递归(也不需要)。要进行递归,您必须从内部调用
    power
    ,您的
    递归
    标签毫无意义。调用
    product
    然后
    power
    推送
    新操作数,并再次调用它,直到满足停止条件(递归…@Tidus)-首先练习调用Convention use-编写简单函数,取2个整数并返回1个整数。根据调用约定,您还必须向调用方添加一些代码-请参阅反汇编和读取中的例程调用。如果你明天做不好,我就帮你;-)啊,我错过了循环中的
    moveax[ebp-4]
    。但是你从来没有实际使用过它,所以最好从循环中删除它。实际上最好完全停止使用[ebp-4],而使用eax寄存器作为变量。最好不要使用循环。:)使用
    mul
    imul
    .1。这不是在产品循环标签中完成的吗?在product_done中,我做了一些事情,比如恢复寄存器、释放局部变量、恢复基指针等,以实现约定。2-3. 我知道这些都是做这些事情的可怕方式,但这是一种试图让我的头脑完全清醒过来的练习。你能告诉我如何使用递归吗?基本上我是在努力实现这一点:在我的能力范围内function@TidusSmith-不,对不起。必须从一开始就阻止不良做法。:)检查我的解决方案。这样好一点吗?老实说,我很高兴它能起作用,但我可以,我应该尽快学会如何正确地做。我真正需要知道并且似乎已经发现的是,传入的参数只是随便什么