鱼C论坛

 找回密码
 立即注册
查看: 3993|回复: 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 | 显示全部楼层
  1. ;递归调用的fibo函数,其中eax寄存器用来传递参数所以不用入栈保存
  2. fibo:
  3.     ;递归返回条件 eax = 1 或 eax = 2
  4.     cmp eax, 1
  5.     je _get_out
  6.     cmp eax, 2
  7.     je _get_out

  8.     push ebx
  9.     push ecx
  10.     push edx
  11.    
  12.         ;递归函数里用到了ebx,ecx,edx三个寄存器,所以这3个寄存器要入栈保存
  13.     mov edx, eax
  14.     sub eax, 1
  15.     call fibo
  16.     mov ebx, eax

  17.     mov eax, edx
  18.     sub eax, 2
  19.     mov ecx, eax

  20.     mov eax, ebx
  21.     add eax, ecx

  22.     pop edx
  23.     pop ecx
  24.     pop ebx

  25. _get_out:
  26.     mov eax, 1
  27.     ret

  28. main:
  29.     mov eax, 7
  30.     call fibo
  31.     ret
复制代码


不过代码似乎有问题
斐波那契的递归写法

  1. long fibo(long i)
  2. {
  3.     if(i <= 2)
  4.         return 1;
  5.    else
  6.         return  fibo(i-1)+fibo(i-2);
  7. }
复制代码
想知道小甲鱼最近在做啥?请访问 -> 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寄存器用来传递参数所以不用入栈保存

  1. fibo:
  2.     ;递归返回条件 eax = 1 或 eax = 2 这个返回条件可以写成 eax <= 2
  3.     ;cmp eax, 1
  4.     ;je _get_out
  5.     ;cmp eax, 2
  6.     ;je _get_out
  7.         cmp  eax,2
  8.         jle  _get_out

  9.     push ebx
  10.     push ecx
  11.     push edx
  12.    
  13.     ;递归函数里用到了ebx,ecx,edx三个寄存器,所以这3个寄存器要入栈保存
  14.         ;用edx来保存eax的值
  15.     mov edx, eax
  16.         ;eax - 1 ,并把eax作为参数递归调用 fibo ,相当于计算 fibo(i - 1)
  17.     sub eax, 1
  18.     call fibo
  19.         ;返回值在eax中,取得返回值保存在ebx中
  20.     mov ebx, eax
  21.    
  22.         ;将之前保存在edx中的参数赋给 eax
  23.     mov eax, edx
  24.         ;eax - 2,并把 eax 作为参数递归调用 fibo ,相当于计算 fibo(i-2)
  25.     sub eax, 2
  26.         ;这里少了一句递归调用
  27.         call fibo
  28.         ;返回值在eax 中,取得返回值并保存进 ecx,当然,这里纯属脱裤子放屁,直接写成 add eax,ebx 即可
  29.     mov ecx, eax
  30.        
  31.         ;取得之前计算的 fibo(i-1)
  32.     mov eax, ebx
  33.         ;计算  fibo(i-1) + fibo(i-2)
  34.     add eax, ecx

  35.     pop edx
  36.     pop ecx
  37.     pop ebx
  38.         ;这里少了一个返回语句,不然返回值 eax 总是1
  39.         ret
  40. _get_out:
  41.     mov eax, 1
  42.     ret

  43. main:
  44.     ;eax = 7 ,调用 fibo ,相当于 fibo(7)
  45.     mov eax, 7
  46.     call fibo
  47.     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-4-28 04:35

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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