一、参数传递方式
- 寄存器传参数
- 将参数值复制到寄存器,但存在缺点,大概无法规复寄存器,导致代码杂乱,使系统无法正常运行。例如在一些操作中,若未正确规复寄存器值,后续步伐实行大概堕落。
- 如代码中常见的先保存寄存器值(如 push ebx、push ecx 等),在子步伐调用结束后再规复(pop esi、pop ecx、pop ebx 等)操作就是为了制止此题目。
- 堆栈传参数
- 在调用子步伐前将参数压入堆栈。有值传递(如 push val2、push val1 后 call AddTwo)和引用传递(如 push OFFSET val2、push OFFSET val1 后 call Swap)两种方式。
- 优点是相对机动,能传递较多参数且不依靠特定寄存器。但需注意堆栈平衡,子步伐返回时要扫除堆栈,否则会导致内存泄露和堆栈粉碎。如在一些示例中,若不清理堆栈,后续步伐获取参数或实行其他操作时会出现错误。
二、堆栈帧
- 创建步调
- 被传递的实际参数(如有)压入堆栈。
- 子步伐调用时,其返回值压入堆栈。
- 子步伐开始实行时,EBP(扩展帧指针寄存器)压入堆栈。
- 设置 EBP 等于 ESP,确立基址。
- 若有局部变量,修改 ESP 为变量留空间。
- 如有其他寄存器要保存,压入堆栈。
- 访问堆栈里的参数:通过 EBP 加上偏移量(堆栈中一个存储 4 字节)来访问,如在 AddTwo 子步伐中,mov eax,[ebp + 12]获取第二个参数,add eax,[ebp + 8]获取第一个参数。
三、调用规范
- 32 位调用规范
- c 语言调用协议:适用于 Unix、Windows。在 Example1 中,call AddTwo 后通过 add esp,8 来扫除堆栈,规复堆栈指针。
- STDCALL 调用协议:用于调用 Windows API 函数协议。在 AddTwo 中,ret 8可扫除堆栈,确保堆栈平衡。
- 本书事例:多采用 STDCALL 调用协议。
四、寄存器保存与规复及局部变量处理
- 寄存器保存与规复:在子步伐中,如 MySub PROC 中,先 push ebp、push ecx、push edx保存相干寄存器,在子步伐结束前 pop edx、pop ecx、pop ebp 规复寄存器,且这种操作不会影响参数与 ESP 的位移量。
- 局部变量处理:在 MySub 等子步伐中,通过 sub esp,8 为局部变量预留空间,如创建局部变量 DWORD PTR [ebp - 4],10 (值 10 存储到[ebp - 4]的内存地址)和 DWORD PTR [ebp - 8],20,末了通过 mov esp,ebp 和 pop ebp 来删除局部变量并规复堆栈。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |