硬件方向个人札记(part 2)
分类:硬件方向个人札记日期:2012-04-15作者:SimolluS Heinz阅读:597 views
有一段时间没有写这方面的东西了,原因很简单,寒假之后由16位汇编转向了32位汇编,显然刚开始非常水,实在不好意思发文章来找鄙视的~直到今天写了一个有点意思的递归程序,虽说班里的大牛,也就是我们的malash同学听说后还是直接把我狠狠鄙视了一顿,觉得这完全是少见多怪递归应该打回去重学的缘故,但是嘛……姑且反以为荣地写一下吧,大牛们轻拍~
这次学习32位汇编使用的教材是《Intel 高级语言程序设计》(第五版),也就是Irvine的那本书,题目出自8.3.3.6,大意是写出生成斐波那契数列的前20个整数的递归算法。利用之前对例题,也就是递归求阶乘的经验,最初对解题过程做此分析:
1:本题与阶乘题的区别在于每一步骤所需的两个操作数都是之前的结果
2:此区别将导致需要在某一或不同位置存入之前两次运算的数据
3:其中一次的数据可以直接由递归过程依次传递,另一次需要长时间保存
故创建堆栈框架如此:
Val20 |
ReturnMain |
EBP0 |
Val19 |
ReturnFact |
EBP1 |
Val18 |
…… |
其中Valn代表在此前的某一次递归中应当引用的另一个“古老”些的数据,首次产生的代码如下图:
主程序中首先初始化参数,将递归次数压入堆栈,进入递归过程。过程中依次将返回地址,EBP,EAX压入堆栈,EBP产生可使用的指针,注意此时的EAX只是起占位作用,无确定值。20次递归调用创建完毕,开始回溯,每次弹出一个EBP值,重新规划数据相对位置随后将之前一次的结果存在稍远一次调用(前溯两次)的预留位上(每前溯一个位置内存指针加4,每一次调用含三个位置,再加上本次还有一个位置未弹出,故每次加上20)。随后逐次将前溯两次所存的数据与上次递归结果相加,打印到显示缓冲区,进入下次递归。
然后进行试验,单步运行,很高兴的发现前几次出现了正确的数据打印,只是到最后显示堆栈引用错误……好吧仔细想想这其实是一件显然的事情,每次将数据存入的位置事实上是之前的一次调用中的,于是回溯到最后一次时必定会造成溢出,那么将存储的位置一次下移一组就好,如图:
好的……然后在还没编译之前就知道是我的脑子被踢到了才会写出这种东西的= =……ret指令已经将ESP寄存器上移到前一次的框架了,也就是说之后再引用【EBP – 4】已经是无效地址!
于是加以修改,很简单,挪动语句顺序即可:
编译运行基本正常,但是发现会在数列最初缺少一个“1”,但是稍微修改之前的边界条件为“-1”就又会多产生一个“0”,于是直接懒得优化代码,规定看到0就不允许打印就算了:
注意比较EAX与“-1”之后的跳转必须使用“jg”,因为引入了有符号数大小比较跳转。
全部完成,测试完美,程序整体与结果打印见下:
总体说来,平心而论这是一个写的还算靠谱的汇编程序,亲测相对最简洁写法的C语言程序执行速率大约提高了75%,但是显然还是可以使用各种手法继续加强效率的,但作为初学也就只好如此而已。
特此
有水平
赞一个,不过看不懂
额,你们好像都很牛的样子