鱼C论坛

 找回密码
 立即注册
查看: 4638|回复: 12

帮忙看下这个简单的汇编程序(函数返回值)

[复制链接]
发表于 2020-10-13 16:30:27 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
global main

fibo:
    cmp eax, 1
    je _get_out
    cmp eax, 2
    je _get_out

    push ebx
    push ecx
    push edx

    mov edx, eax
    sub eax, 1
    call fibo
    mov ebx, eax

    mov eax, edx
    sub eax, 2
    mov ecx, eax

    mov eax, ebx
    add eax, ecx

    pop edx
    pop ecx
    pop ebx

_get_out:
    mov eax, 1
    ret

main:
    mov eax, 7
    call fibo
    ret

如上一个简单的求Fibonoacci数的汇编程序段
为啥eax不需要压栈????不需要保存eax的状态吗?那为啥ebx、ecx、edx需要呢,有啥区别?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-10-13 17:06:36 | 显示全部楼层
;递归调用的fibo函数,其中eax寄存器用来传递参数所以不用入栈保存
fibo:
    ;递归返回条件 eax = 1 或 eax = 2 
    cmp eax, 1
    je _get_out
    cmp eax, 2
    je _get_out

    push ebx
    push ecx
    push edx
    
        ;递归函数里用到了ebx,ecx,edx三个寄存器,所以这3个寄存器要入栈保存
    mov edx, eax
    sub eax, 1
    call fibo
    mov ebx, eax

    mov eax, edx
    sub eax, 2
    mov ecx, eax

    mov eax, ebx
    add eax, ecx

    pop edx
    pop ecx
    pop ebx

_get_out:
    mov eax, 1
    ret

main:
    mov eax, 7
    call fibo
    ret

不过代码似乎有问题
斐波那契的递归写法
long fibo(long i)
{ 
    if(i <= 2)
        return 1;
   else
        return  fibo(i-1)+fibo(i-2);
}
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-10-13 19:14:43 | 显示全部楼层
xieglt 发表于 2020-10-13 17:06
不过代码似乎有问题
斐波那契的递归写法

谢谢回复。那么为啥eax就不用保存呢,在调用这个fibo函数之前,eax不也有值的吗?和ebx、ecx、edx有啥区别呢?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-10-13 19:15:16 | 显示全部楼层
xieglt 发表于 2020-10-13 17:06
不过代码似乎有问题
斐波那契的递归写法

代码不是我写的,是知乎上看到的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-10-14 09:06:18 | 显示全部楼层
爷就是爷 发表于 2020-10-13 19:15
代码不是我写的,是知乎上看到的

详细注释了一下,能看懂吗
;递归调用的fibo函数,其中eax寄存器用来传递参数所以不用入栈保存
fibo:
    ;递归返回条件 eax = 1 或 eax = 2 这个返回条件可以写成 eax <= 2 
    ;cmp eax, 1
    ;je _get_out
    ;cmp eax, 2
    ;je _get_out
        cmp  eax,2
        jle  _get_out

    push ebx
    push ecx
    push edx
    
    ;递归函数里用到了ebx,ecx,edx三个寄存器,所以这3个寄存器要入栈保存
        ;用edx来保存eax的值
    mov edx, eax
        ;eax - 1 ,并把eax作为参数递归调用 fibo ,相当于计算 fibo(i - 1)
    sub eax, 1
    call fibo
        ;返回值在eax中,取得返回值保存在ebx中
    mov ebx, eax
    
        ;将之前保存在edx中的参数赋给 eax
    mov eax, edx
        ;eax - 2,并把 eax 作为参数递归调用 fibo ,相当于计算 fibo(i-2)
    sub eax, 2
        ;这里少了一句递归调用
        call fibo
        ;返回值在eax 中,取得返回值并保存进 ecx,当然,这里纯属脱裤子放屁,直接写成 add eax,ebx 即可
    mov ecx, eax
        
        ;取得之前计算的 fibo(i-1)
    mov eax, ebx
        ;计算  fibo(i-1) + fibo(i-2)
    add eax, ecx

    pop edx
    pop ecx
    pop ebx
        ;这里少了一个返回语句,不然返回值 eax 总是1
        ret
_get_out:
    mov eax, 1
    ret

main:
    ;eax = 7 ,调用 fibo ,相当于 fibo(7)
    mov eax, 7
    call fibo
    ret
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-10-15 16:18:41 | 显示全部楼层
为什么要在函数执行前入将各寄存器中的值入栈呢?是为了这个函数执行完后CPU能返回到函数执行前的环境,也就是先把原来寄存器中的值寄存在栈中,当当前程序执行完后CUP还要取回原来寄存器中的值,继续之前的工作。但是这里为什么没有把EAX的值入栈保存呢?EAX是累加器,主要用来传参的,这时候CPU认为它里面原来是什么不重要,所以没有将它的值入栈保存。简而言之,EAX可入栈也可不入栈,因为它不重要,所以没入栈。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-10-17 22:42:59 | 显示全部楼层
兔子不说话 发表于 2020-10-15 16:18
为什么要在函数执行前入将各寄存器中的值入栈呢?是为了这个函数执行完后CPU能返回到函数执行前的环境,也 ...

是因为(E)AX比较特殊吗?eax和ebx、ecx一样在调用之前肯定也有数据,这里的数据是不重要的对吗?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-10-18 10:39:42 | 显示全部楼层
是的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2020-10-18 17:49:03 | 显示全部楼层

eax、ebx不都是数据寄存器吗?
有啥不同,这样说CX还存放循环变量的值,不也可以随便放脏数据吗,反正都要被覆盖掉?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-10-18 19:38:44 | 显示全部楼层
只是程序的编写者觉得这个寄存器中的数据不重要所以没有入栈,通常这样写也不会出什么大问题,在规范的汇编语言上所有寄存器的值都是应该在使用前入栈保存的。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-10-19 03:56:33 | 显示全部楼层
兔子不说话 发表于 2020-10-18 19:38
只是程序的编写者觉得这个寄存器中的数据不重要所以没有入栈,通常这样写也不会出什么大问题,在规范的汇编 ...

你确定?are you sure?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-10-19 08:32:49 | 显示全部楼层
嗯,最开始提出过类似的问题,当时那段程序是ECX没有入栈。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-11-16 13:00:15 | 显示全部楼层
萌出血 发表于 2020-10-19 03:56
你确定?are you sure?

这些寄存器怎么用,书上只是提出了惯例,惯例是很多人一起写程序形成的,如果你知道了惯例,看别人写的程序时,就容易看懂些。
你完全可以自己改变这些寄存器的用法(特殊的除外),你想用它做什么就是什么?毕竟计算机并不知道什么是惯例。比如说,你一定要EBX做计次用,一定要用EDX做累加用,计算机也拿你没办法。

本程序EAX不需要入栈,是因为在作者的这个程序中,EAX可以不入栈。
入栈的都是为了在现在保存结果(入栈的主要用途),以备将来使用,这样可以节约寄存器。

为什么要节约寄存器,那是因为在远古时代(扯远了,其实就是计算机刚发明时)寄存器很珍贵,非常珍贵,必须节约、有效利用。所以一代一代这么传下来了。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-11-6 10:53

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表