汇编语言全接触-75.汇编中参数的传递和堆栈修正

在 Win32汇编中,我们经常要和 Api 打交道,另外也会常常使用自己编制的类似于 Api 的带参数的子程序,本文要讲述的是在子程序调用的过程中进行参数传递的概念和分析。一般在程序中,参数的传递是通过堆栈进行的,也就是说,调用者把要传递给子程序(或者被调用者)的参数压入堆栈,子程序在堆栈取出相应的值再使用,比如说,如果你要调用 SubRouting(Var1,Var2,Var3),编译后的最终代码可能是

push Var3

push Var2

push Var1

call SubRouting

add esp,12

也就是说,调用者首先把参数压入堆栈,然后调用子程序,在完成后,由于堆栈中先前压入的数不再有用,调用者或者被调用者必须有一方把堆栈指针修正到调用前的状态。参数是最右边的先入堆栈还是最左边的先入堆栈、还有由调用者还是被调用者来修正堆栈都必须有个约定,不然就会产生不正确的结果,这就是我在前面使用“可能”这两个字的原因:各种语言中调用子程序的约定是不同的,它们的不同点见下表:

C

SysCall

StdCall

Basic

Fortran

Pascal

参数从左到右

参数从右到左

调用者清除堆栈

允许使用:VARARG

VARARG 表示参数的个数可以是不确定的,有一个例子就是 C 中的 printf 语句,在上表中,StdCall 的定义有个要说明的地方,就是如果 StdCall 使用 :VARARG 时,是由调用者清除堆栈的,而在没有:VARARG时是由被调用者清除堆栈的。

在 Win32 汇编中,约定使用 StdCall 方式,所以我们要在程序开始的时候使用 .model stdcall 语句。也就是说,在 API 或子程序中,最右边的参数先入堆栈,然后子程序在返回的时候负责校正堆栈,举例说明,如果我们要调用 MessageBox 这个 API,因为它的定义是 MessageBox(hWnd,lpText,lpCaption,UType) 所以在程序中要这样使用:

push MB_OK

push offset szCaption

push offset szText

push hWnd

call MessageBox

...

我们不必在 API 返回的时候加上一句 add sp,4*4 来修正堆栈,因为这已经由 MessageBox 这个子程序做了。在 Windows API 中,唯一一个特殊的 API 是 wsprintf,这个 API 是 C 约定的,它的定义是 wsprintf(lpOut,lpFormat,Var1,Var2...),所以在使用时就要:

push 1111

push 2222

push 3333

push offset szFormat

push offset szOut

call wsprintf

add esp,4*5

下面要讲的是子程序如何存取参数,因为缺省对堆栈操作的寄存器有 ESP 和 EBP,而 ESP是堆栈指针,无法暂借使用,所以一般使用 EBP 来存取堆栈,假定在一个调用中有两个参数,而且在 push 第一个参数前的堆栈指针 ESP 为 X,那么压入两个参数后的 ESP 为 X-8,程序开始执行 call 指令,call 指令把返回地址压入堆栈,这时候 ESP 为 X-C,这时已经在子程序中了,我们可以开始使用 EBP 来存取参数了,但为了在返回时恢复 EBP 的值,我们还是再需要一句 push ebp 来先保存 EBP 的值,这时 ESP 为 X-10,再执行一句 mov ebp,esp,根据右图可以看出,实际上这时候 [ebp + 8] 就是参数1,[ebp + c]就是参数2。另外,局部变量也是定义在堆栈中的,它们的位置一般放在 push ebp 保存的 EBP 数值的后面,局部变量1、2对应的地址分别是 [ebp-4]、[ebp-8],下面是一个典型的子程序,可以完成第一个参数减去第二个参数,它的定义是:

MyProc proto Var1,Var2 ;有两个参数

local lVar1,lVar2 ;有两个局部变量

注意,这里的两个 local 变量实际上没有被用到,只是为了演示用,具体实现的代码是:

MyProc proc

push ebp

mov ebp,esp

sub esp,8

mov eax,dword ptr [ebp + 8]

sub eax,dword ptr [ebp + c]

add esp,8

pop ebp

ret 8

MyProc endp

现在对这个子程序分析一下,push ebp/mov ebp,esp 是例行的保存和设置 EBP 的代码,sub esp,8 在堆栈中留出两个局部变量的空间,mov /add 语句完成相加,add esp,8 修正两个局部变量使用的堆栈,ret 8 修正两个参数使用的堆栈,相当于 ret / add esp,8 两句代码的效果。可以看出,这是一个标准的 Stdcall 约定的子程序,使用时最后一个参数先入堆栈,返回时由子程序进行堆栈修正。当然,这个子程序为了演示执行过程,使用了手工保存 ebp 并设置局部变量的方法,实际上,386 处理器有两条专用的指令是完成这个功能用的,那就是 Enter 和 Leave,Enter 语句的作用就是 push ebp/mov ebp,esp/sub esp,xxx,这个 xxx 就是 Enter 的,Leave 则完成 add esp,xxx/pop ebp 的功能,所以上面的程序可以改成:

MyPorc proc

enter 8,0

mov eax,dword ptr [ebp + 8]

sub eax,dword ptr [ebp + c]

leave

ret 8

MyProc endp

好了,说到这儿,参数传递的原理也应该将清楚了,还要最后说的是,在使用 Masm32 编 Win32 汇编程序的时候,我们并不需要记住 [ebp + xx] 等麻烦的地址,或自己计算局部变量需要预留的堆栈空间,还有在 ret 时计算要加上的数值,Masm32 的宏指令都已经把这些做好了,如在 Masm32 中,上面的程序只要写成为:

MyProc proc Var1,Var2

local lVar1,lVar2

mov eax,Var1

sub eax,Var2

ret

MyProc endp

编译器会自动的在 mov eax,Var1 前面插上一句 Enter 语句,它的参数会根据 local 定义的局部变量的多少自动指定,在 ret 前会自动加上一句 Leave,同样,编译器会根据参数的多少把 ret 替换成 ret xxx,把 mov eax,Var1 换成 mov eax,dword ptr [ebp + 8] 等等。

最后是使用 Masm32 的 invoke 宏指令,在前面可以看到,调用带参数的子程序时,我们需要用 push 把参数压入堆栈,如果不小心把参数个数搞错了,就会使堆栈不平衡,从而使程序从堆栈中取出错误的返回地址引起不可预料的后果,所以有必要有一条语句来完成自动检验的任务,invoke 就是这样的语句,实际上,它是自动 push 所有参数,检测参数个数、类型是否正确,并使用 call 来调用的一个宏指令,对于上面的 push/push/call MyProc 的指令,可以用一条指令完成就是:

invoke MyProc,Var1,Var2

当然,当程序编译好以后你去看机器码会发现它被正确地换成了同样的 push/push/call 指令。但是,在使用 invoke 之前,为了让它进行正确的参数检验,你需要对函数进行申明,就象在 C 中一样,申明的语句是:

MyProc proto :DWORD,:DWORD

语句中 proto 是关键字,表示申明,:DWORD 表示参数的类型是 double word 类型的,有几个就表示有几个参数,在 Win32 中参数都是 double word 型的,申明语句要写在 invoke 之前,所以我们一般把它包括在 include 文件中,好了,综合一下,在 Masm32 中使用一个带参数的子程序或者 Api ,我们只需用:

...

MyProc proto :dword,:dword

...

.data

x dd ?

y dd ?

dwResult dd ?

...

mov x,1

mov y,2

invoke MyProc x,y

mov dwResult,eax

...

就行了,如何,是不是很简单啊?不过我可苦了,这篇文章整整花了我一个晚上 ... ##%$^&(*&^(*&(^&(* ...

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1129494.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

吉时利2000 六位半万用表 keithley2000

keithley2000六位半万用表是吉时利的高性能dmm系列的一款。基于与2001和2002款相同的高速、低噪音A/D转换器技术,2000是一种快速、准确、高度稳定的仪器,易于操作方便。它结合了广泛的测量范围和优越的精度规范——从100nV到1天的直流电压kV(…

阿里云渠道商:阿里云弹性伸缩有哪几种

一、引言在云计算时代,业务流量常呈现周期性波动或突发性增长。阿里云弹性伸缩(Auto Scaling)作为核心服务,能自动调整计算资源,既避免资源浪费,又保障业务稳定性。本文将系统解析阿里云弹性伸缩的四大类型…

2026年TOP5EOR名义雇主服务优势推荐榜单,引领企业高效国际化扩展

EOR名义雇主服务在企业国际化扩展过程中扮演着重要角色。通过这一服务,企业能够合法地雇佣外籍员工,避免了注册当地公司的繁琐程序。特别是在合规保障方面,EOR名义雇主提供全面的法律支持,使得企业可以高效、安全地进入新市场。此…

本地部署服务器搭建工具 PHPStudy 并实现外部访问

PHStudy 是一款便携的服务器环境搭建工具,能够减少 单独部署各个软件的麻烦。能够一键创建网站、FTP、数据库等功能,支持安全管理、计划任务、文件管理。是用于个人、小型团队和初学者。本文将详细介绍如何在本地安装 PHStudy 以及结合路由侠内网穿透实现…

轻量级AI应用崛起:M2FP CPU版成中小企业首选方案

轻量级AI应用崛起:M2FP CPU版成中小企业首选方案 随着人工智能技术从“大模型、重算力”向“轻量化、可落地”演进,越来越多的中小企业开始关注低成本、高稳定性、无需GPU即可运行的AI解决方案。在图像语义分割领域,M2FP(Mask2For…

[大模型架构] LangGraph AI 工作流编排(5)

一、ElectronForge 的核心价值:为何选择它初始化项目?视频开篇明确了 ElectronForge 的定位 ——Electron 官方推荐的项目脚手架工具,其核心优势在于解决传统 Electron 项目 “初始化繁琐、配置分散、打包部署复杂” 的痛点,尤其适…

实时性能优化:M2FP的线程池配置指南

实时性能优化:M2FP的线程池配置指南 📌 背景与挑战:多人人体解析服务的并发瓶颈 随着视觉AI在虚拟试衣、动作分析、智能安防等场景中的广泛应用,多人人体解析(Multi-person Human Parsing) 成为一项关键基础…

M2FP模型在数字营销中的应用:个性化广告生成

M2FP模型在数字营销中的应用:个性化广告生成 引言:从人体解析到精准营销的跨越 在数字营销领域,用户注意力的竞争日趋白热化。传统的广告投放方式依赖人口统计学或行为数据进行粗粒度定向,难以实现真正意义上的“千人千面”。而随…

M2FP模型部署实战:Flask Web服务搭建全流程

M2FP模型部署实战:Flask Web服务搭建全流程 🧩 项目背景与核心价值 在计算机视觉领域,人体解析(Human Parsing) 是一项关键的细粒度语义分割任务,旨在将人体分解为多个语义明确的身体部位,如头…

M2FP在虚拟旅游中的应用:人物场景融合

M2FP在虚拟旅游中的应用:人物场景融合 背景与挑战:虚拟旅游中的人物交互需求 随着元宇宙和数字孪生技术的快速发展,虚拟旅游正从静态浏览向沉浸式交互演进。用户不再满足于“看”一个虚拟景点,而是希望“进入”其中,以…

图像处理卡顿?M2FP内置OpenCV加速,CPU推理效率提升2倍

图像处理卡顿?M2FP内置OpenCV加速,CPU推理效率提升2倍 📖 项目简介:M2FP 多人人体解析服务(WebUI API) 在图像语义分割领域,人体解析是一项极具挑战性的任务——不仅要识别出图中每个人物的存…

AI辅助动画制作:M2FP提取角色身体区域加速后期处理

AI辅助动画制作:M2FP提取角色身体区域加速后期处理 在数字内容创作领域,尤其是动画与视觉特效制作中,角色身体区域的精确分割是实现高效后期处理的关键前提。传统手动抠图或基于简单边缘检测的工具已难以满足现代高精度、大批量的生产需求。随…

M2FP WebUI使用全攻略:上传图片→自动拼图→下载结果三步走

M2FP WebUI使用全攻略:上传图片→自动拼图→下载结果三步走 🌟 为什么需要多人人体解析? 在计算机视觉领域,人体解析(Human Parsing) 是语义分割的一个精细化分支,目标是将人体划分为多个具有…

emupedia游戏开发:M2FP为角色动画提供姿态参考数据

emupedia游戏开发:M2FP为角色动画提供姿态参考数据 在现代游戏与动画制作中,高精度的角色姿态捕捉与语义理解是提升内容生产效率的关键环节。传统动作捕捉依赖昂贵设备和专业演员,而基于视觉的自动化人体解析技术正逐步成为低成本、高可用的替…

2008-2024年上市公司超额管理费用、企业寻租数据+stata代码

一、数据介绍 数据名称:超额管理费用/企业寻租数据 样本范围:全部A股上市公司,4.8w观测值(已剔除已缩尾,有代码,可以去除相对应代码得出未剔除未缩尾结果) 数据格式:excel&#x…

南柯电子|汽车电子EMC测试系统:车企必须要知道的电磁安全方案

在汽车智能化、电动化浪潮的推动下,一辆现代汽车搭载的电子控制单元(ECU)数量已突破200个,这些设备在0.1秒内需完成数百万次数据交互,同时需应对高压电机、5G通信、毫米波雷达等产生的复杂电磁环境。若缺乏电磁兼容性&…

数字藏品破局三板斧:技术、内容、合规如何重构行业新生态?

引言:当数字藏品市场陷入"千藏一面"的困局2025年的数字藏品市场正经历着冰火两重天:一边是超过800家平台在红海中激烈厮杀,另一边却是用户留存率持续走低,行业平均用户活跃周期不足3个月。这种"虚假繁荣"背后…

智能镜子开发日记:集成M2FP实现实时人体分割显示

智能镜子开发日记:集成M2FP实现实时人体分割显示 在智能硬件与AI融合的浪潮中,智能镜子正从概念走向落地。它不再只是反射影像的玻璃,而是具备感知、理解甚至交互能力的“数字镜像终端”。其中,实时人体语义分割是实现虚拟试衣、…

2030年,16万亿美元资产将“活”过来:RWA如何改写金融规则?

引言:一场静默的金融革命正在重塑世界当一幅数字藏品以百万美元成交、一座光伏电站的收益权被拆分成数万份全球流通、甚至一栋纽约豪宅的产权被“碎片化”交易时,现实世界资产(RWA,Real World Assets)的数字化浪潮已不…

DApp革命:当代码重构信任,去中心化应用开启数字主权新纪元

引言:一场静默的权力转移 2025年,全球区块链用户突破5亿,DeFi锁仓量超2万亿美元,NFT市场年交易额达800亿美元——这些数字背后,是一场关于数据主权、价值分配与信任机制的底层革命。当传统互联网巨头因数据泄露、算法…