函数
1、函数的识别
程序通过调用函数,在函数执行后又返回调用程序继续执行,此时是通过定位call机器指令和利用ret指令结束的标志来识别函数,最简单的示例:
虽然是个小程序,但是写出汇编还是花了不少时间:
自己写完,再对比书上的:
感觉自己对比vc环境写的有些复杂,于是想优化一下:
似乎没有多大的变化,差不多只是调整了一下位置。
我又一个疑问,就是前后L1处的汇编代码,我有点想不通为什么前者是ebp为基础,后者esp为基础时,它怎么确定这两个未知的数都是指的同一个地方!
2、函数的参数
函数传递参数有三种形式:栈方式、寄存器方式以及通过全局变量进行隐含参数传递的方式。经过十几天汇编学习,其中用得最多的就是前两种:
当参数是通过栈传递的时候,就要定义参数在栈中的顺序,并约定函数被调用后由谁来平衡栈。而平衡栈对于我来说隐隐约约感觉是一个难点。
当参数是通过寄存器传递的,就要确定参数放在哪个寄存器中。之前的学习,发现函数返回时基本都是保存在eax中。
#include<stdio.h>
int Add(int x, int y);
void main()
{
char *str="total=%d\n";
_asm
{
push 3
push 2
call L1
jmp L2
L1:
push ebp
mov ebp,esp
mov eax,dword ptr [ebp+8]
mov ecx,dword ptr [ebp+0Ch]
add eax,ecx
mov esp,ebp
pop ebp
retn
L2:
add esp,8
push eax
push str
call printf
add esp,8
}
}
似乎明白了一些上面的困惑:
因为esp是栈指针,所以一般使用ebp来存取栈。esp在栈的执行过程中随时都在变,所以我们还是一般使用ebp。
随后第一次接触有关类的汇编:
在我的印象中,C语言似乎是没有类的,(在我之前学的C语言),但是还是运行实现了:
接下来,万成不变的就是进入调试状态写出汇编,经过调试,我发现与之前调用没有什么区别:
但是我又发现call指令之前相比之前是多了一句lea指令!可能差别就在这儿吧!