为什么学习本节内容?因为我们要学习汇编语言中参数传递的方式,而堆栈传参会使我们工作效率提高。
本节必须掌握的知识点:
掌握参数传递的方式
熟练使用堆栈传参
我们无论学习什么语言,都离不开函数、参数、参数传递、函数调用、返回值等这几个步骤。在上节中我们介绍了函数及函数调用并简略的说了一下参数、参数传递、返回值。本节将继续探讨参数传递。
2.13.1【参数传递方式】
参数传递的方式有两种:
1、寄存器传参
2、堆栈传参
【寄存器传参的方式】
在上一节中我们做了一个例子,编写一个函数,实现任意两个整数相加,就是用的寄存器传参的方式介绍的,下面是完整代码。
MOV ECX ,1
MOV EDX ,2
CALL 0x77068E51 (注:CALL后面跟的地址要根据你自己编写的函数实际情况来定)
这里是函数体,实现任意2个整数相加的函数
0x77068E51 ADD ECX,EDX (ECX存储的数据 EDX存储的数据的值保存到ECX中)
MOV EAX,ECX (所得到的结果放到EAX中)
RETN
已经写出来了代码,可还是不知道什么是寄存器传参。我们分析上面代码来介绍寄存器传参。
根据题意知,任意两个整数,这里知道这两个整数是存在,根据代码可知我们假设的这两个整数分别为1、2,那存在哪里呢?根据
MOV ECX,1
MOV EDX,2
可知把1保存在了ECX中,把2保存在了EDX中,ECX、EDX大家都知道这是寄存器,把两个整数保存在了寄存器里,执行CALL指令后,重点来了。
根据
ADD ECX,EDX
MOV EAX,ECX
这两行指令我们知道了,实现两个整数相加的功能,是通过寄存器中保存的数据相互做运算的,运算的结果保存在了EAX中。这是我们自己约定用寄存器传参的方式。
总结:我们在编写一个汇编函数时,用寄存器传参的方式,要提前约定好参与函数功能的寄存器,将参数存入函数约定好的寄存器中,在进行运算。
那么问题来了,我们知道的寄存器也就那么几十个,如果一个函数需要传递大量的参数,显然寄存器是不够用的,那该怎么解决哪?需要用到堆栈传参的方式去解决。
【堆栈传参的方式】
堆栈传参看到这几个字肯定能想到将参数保存在堆栈中。那我们该怎么用哪?同样用例题介绍堆栈传参的方式。
例:编写一个函数,实现任意五个整数相加。
分析:需要将5个参数保存到堆栈中,用CALL指令调用函数。
第一步:在DTDebug.exe软件中打开飞鸽软件,如图2-13-1所示。
第二步:将5个整数压入堆栈,输入以下指令,如图2-13-2所示。
PUSH 1
PUSH 2
PUSH 3
PUSH 4
PUSH 5
第三步:依次按F8将参数压入堆栈中,如图2-13-3所示。
按F8执行完看到,堆栈中已经压入我们传递的参数。用CALL调用函数,我们怎么编写这个函数哪?
我们的常用指令不允许两边都为内存,所以我们通过ESP栈顶指针来运算。
如果这么写:MOV EAX,DWORD PTR DS:[ESP],那么EAX里的值是什么?
我们编写完参数后,调用CALL,会将CALL下一行的指令地址传入堆栈,这个时候ESP的值就是CALL函数地址,堆栈的变化如图2-13-4:
图2-13-4 堆栈图
第三步:编写函数,输入以下指令,如图2-13-5所示。
这5个参数依次是:ESP 0x14、ESP 0x10、ESP 0xC、ESP 0x8、ESP 0x4
所以我们的函数可以这样编写:
MOV EAX,DWORD PTR DS:[ESP 0x14]
ADD EAX,DWORD PTR DS:[ESP 0x10]
ADD EAX,DWORD PTR DS:[ESP 0xC]
ADD EAX,DWORD PTR DS:[ESP 0x8]
ADD EAX,DWORD PTR DS:[ESP 0x4]
RETN
第四步:使用CALL调用函数,输入CALL 0x77068E4D,如图2-13-6所示。
第五步:按F7观察堆栈窗口数据变化,如图2-13-7所示。
图2-13-7中,执行完CALL指令,并将CALL指令下一行地址压入堆栈中,当前黑色定位光标在函数体开始的地址,当前ESP是0x0019FFD8,堆栈窗口中的内存使用是从高地址向低地址使用的,所以ESP 14是参数的开始。我们可以双击堆栈窗口中的内存地址,如图2-13-8所示。
第六步:把EAX寄存器的数据变为0x00000000,依次按F8,查看结果是否正确,如图2-13-9所示。
1 2 3 4 5=15,转化成16进制为F。看图2-13-9中,EAX寄存器的值为0x00000000F,说明运算结果正确,证明我们编写的函数是正确的。
第七步:按F8执行RETN指令,如图2-13-10所示。
以上是堆栈传参的过程,总结:堆栈传参是将参数压入堆栈中,函数在运算时通过ESP寻址的方式去查找对应的参数并进行运算。
那么问题来了,我们的函数执行完了,可是我们的数据还保存在堆栈中,该怎么解决呢?
下节我们解答这个问题。
下节介绍堆栈平衡。
练习:
1、用汇编编写一个函数,功能是实现对任意10个整数的加法运算(不考虑溢出),
要求:
1、前两个参数使用寄存器进程参数传递;
2、后8个参数使用堆栈进行传递。
Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved