爷就是爷 发表于 2020-10-13 16:30:27

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

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需要呢,有啥区别?

xieglt 发表于 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
      returnfibo(i-1)+fibo(i-2);
}

爷就是爷 发表于 2020-10-13 19:14:43

xieglt 发表于 2020-10-13 17:06
不过代码似乎有问题
斐波那契的递归写法

谢谢回复。那么为啥eax就不用保存呢,在调用这个fibo函数之前,eax不也有值的吗?和ebx、ecx、edx有啥区别呢?

爷就是爷 发表于 2020-10-13 19:15:16

xieglt 发表于 2020-10-13 17:06
不过代码似乎有问题
斐波那契的递归写法

代码不是我写的,是知乎上看到的

xieglt 发表于 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
        cmpeax,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

兔子不说话 发表于 2020-10-15 16:18:41

为什么要在函数执行前入将各寄存器中的值入栈呢?是为了这个函数执行完后CPU能返回到函数执行前的环境,也就是先把原来寄存器中的值寄存在栈中,当当前程序执行完后CUP还要取回原来寄存器中的值,继续之前的工作。但是这里为什么没有把EAX的值入栈保存呢?EAX是累加器,主要用来传参的,这时候CPU认为它里面原来是什么不重要,所以没有将它的值入栈保存。简而言之,EAX可入栈也可不入栈,因为它不重要,所以没入栈。

爷就是爷 发表于 2020-10-17 22:42:59

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

是因为(E)AX比较特殊吗?eax和ebx、ecx一样在调用之前肯定也有数据,这里的数据是不重要的对吗?

兔子不说话 发表于 2020-10-18 10:39:42

是的

爷就是爷 发表于 2020-10-18 17:49:03

兔子不说话 发表于 2020-10-18 10:39
是的

eax、ebx不都是数据寄存器吗?
有啥不同,这样说CX还存放循环变量的值,不也可以随便放脏数据吗,反正都要被覆盖掉?

兔子不说话 发表于 2020-10-18 19:38:44

只是程序的编写者觉得这个寄存器中的数据不重要所以没有入栈,通常这样写也不会出什么大问题,在规范的汇编语言上所有寄存器的值都是应该在使用前入栈保存的。

萌出血 发表于 2020-10-19 03:56:33

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

你确定?are you sure?

兔子不说话 发表于 2020-10-19 08:32:49

嗯,最开始提出过类似的问题,当时那段程序是ECX没有入栈。

兰陵月 发表于 2020-11-16 13:00:15

萌出血 发表于 2020-10-19 03:56
你确定?are you sure?

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

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

为什么要节约寄存器,那是因为在远古时代(扯远了,其实就是计算机刚发明时)寄存器很珍贵,非常珍贵,必须节约、有效利用。所以一代一代这么传下来了。
页: [1]
查看完整版本: 帮忙看下这个简单的汇编程序(函数返回值)