开启辅助访问 切换到宽版

精易论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

用微信号发送消息登录论坛

新人指南 邀请好友注册 - 我关注人的新帖 教你赚取精币 - 每日签到


求职/招聘- 论坛接单- 开发者大厅

论坛版规 总版规 - 建议/投诉 - 应聘版主 - 精华帖总集 积分说明 - 禁言标准 - 有奖举报

查看: 250|回复: 9
收起左侧

[已解决] 汇编平衡堆栈的问题,刚才帖子重复了

 关闭 [复制链接]
结帖率:71% (17/24)
发表于 2024-11-8 10:10:07 | 显示全部楼层 |阅读模式   湖南省怀化市
8精币
屏幕截图 2024-11-08 091254.png
比如
push 参数1
push 参数2
call ***
ret 0x8
这里清理栈上的8字节

而上图没有 ret 参数数量*4
代码中的确push了参数,这里为什么不需要平栈

上一个帖子有大佬解答了:汇编堆栈平衡问题_精易论坛,就是这个帖子中1楼的问题,没有解决另一个问题




补充内容 (2024-11-8 10:16):
主要就是想知道在什么情况下需要平衡堆栈,什么情况不需要

push 参数1
call ***
pop 参数1
ret
这样可以吗

补充内容 (2024-11-8 10:28):
2楼有个补充图

最佳答案

查看完整内容

说个具体的例子,常用的主要是stdcall和cdecl stdcall函数: (假设此时esp=0x4) push 0x0 (上面push完此时esp=0x0) call 函数地址 (上面call完此时esp=0x4,和调用前保持了一致) 调用完成 cdecl函数: (假设此时esp=0x4) push 0x0 (上面push完此时esp=0x0) call 函数地址 (上面call完此时esp=0x0) add esp, 0x4 (所以需要add esp, 0x4来还原esp) 调用完成 ...

回答提醒:如果本帖被关闭无法回复,您有更好的答案帮助楼主解决,请发表至 源码区 可获得加分喔。
友情提醒:本版被采纳的主题可在 申请荣誉值 页面申请荣誉值,获得 1点 荣誉值,荣誉值可兑换荣誉会员、终身vip用户组。
快捷通道:申请荣誉值无答案申请取消悬赏投诉有答案未采纳为最佳

签到天数: 17 天

发表于 2024-11-8 10:10:08 | 显示全部楼层   福建省福州市
说个具体的例子,常用的主要是stdcall和cdecl

stdcall函数:
(假设此时esp=0x4)
push 0x0
(上面push完此时esp=0x0)
call 函数地址
(上面call完此时esp=0x4,和调用前保持了一致)
调用完成

cdecl函数:
(假设此时esp=0x4)
push 0x0
(上面push完此时esp=0x0)
call 函数地址
(上面call完此时esp=0x0)
add esp, 0x4 (所以需要add esp, 0x4来还原esp)
调用完成
回复

使用道具 举报

结帖率:71% (17/24)

签到天数: 12 天

 楼主| 发表于 2024-11-8 10:28:27 | 显示全部楼层   湖南省怀化市
屏幕截图 2024-11-08 102650.png
如这里没有push 为什么还要弹出4字节

点评

因为易语言的子程序都是stdcall,所以子程序在返回时要根据参数来平衡堆栈,你子程序内call其它函数,是其它函数的事。你这里ret是只管自身函数的   福建省福州市  发表于 2024-11-8 10:44
回复

使用道具 举报

签到天数: 17 天

发表于 2024-11-8 10:42:58 | 显示全部楼层   福建省福州市
刚看到,首先你要明白平栈的目的是什么,是为了call完后esp保持和call之前的值是一致的,这样才不会影响上层函数。
至于是否需要还原,要看函数的调用约定,有些约定是函数内部平栈了例如:stdcall、fastcall,而cdecl约定需要调用者自行平栈。
简单的说就是看目标函数内部是否处理了堆栈平衡,没处理就需要call完后 add esp, * 之类的操作来平衡esp。
回复

使用道具 举报

结帖率:71% (17/24)

签到天数: 12 天

 楼主| 发表于 2024-11-8 10:55:37 | 显示全部楼层   湖南省怀化市
风行无忌 发表于 2024-11-8 10:42
刚看到,首先你要明白平栈的目的是什么,是为了call完后esp保持和call之前的值是一致的,这样才不会影响上 ...

你看图中,这个图中也是调用一个子程序,直接是用ret返回而不是ret ***
这个是远程调用把机器码写入目标内存,比如我远程调用了他,这段代码本身不是不一个子程序,如果是,它为什么没有平栈,或着说他的写法是错误的,应该ret 0x* 而不是ret ,应为我是看源码学习的,在我的理解中,这段汇编代码就是一个子程序(可能我的理解有误),然后我调用了这段代码,stdcall是被调用者恢复堆栈,可是这段代码中却没有对堆栈进行平衡

补充内容 (2024-11-8 10:56):
这段代码本身是不是不一个子程序,上面打错了

点评

因为这个子程序是stdcall,别人调用它时传了一个参数,这个子程序要负责平衡esp,所以返回时就需要ret 0x4   福建省福州市  发表于 2024-11-8 11:08
回复

使用道具 举报

结帖率:60% (3/5)

签到天数: 22 天

发表于 2024-11-8 11:36:47 | 显示全部楼层   广西壮族自治区柳州市
stdcall是被调用者清栈,也就是函数清理自身参数,push进去啊的函数参数不归你管,由你call的函数去清理
回复

使用道具 举报

结帖率:71% (17/24)

签到天数: 12 天

 楼主| 发表于 2024-11-8 11:50:47 | 显示全部楼层   湖南省怀化市
风行无忌 发表于 2024-11-8 10:58
说个具体的例子,常用的主要是stdcall和cdecl

stdcall函数:

结合你之前说的我好像有点明白了,你看是不是这样

如你点评所说:(因为易语言的子程序都是stdcall,所以子程序在返回时要根据参数来平衡堆栈,你子程序内call其它函数,是其它函数的事。你这里ret是只管自身函数的 )

假设我现在正在编写易语言子程序,子程序中有2个整数型参数,我在这个子程序中使用内联汇编(目的是call或着jmp另一个子程序)
我的理解如下:
1.这个子程序是被调用者,它负责平衡堆栈,无论我在其中call或着jmp另一个子程序(被调用者),栈的平衡由被调用则负责,我不需要管,我负责我自己的子程序
2.如果我使用了 ret 指令返回,不管我有没有使用 push 指令,只要这个子程序有参数,我必须要对堆栈进行平衡
3.我使用了 push 指令压入参数,我没有使用 ret 指令返回,而使用易语言命令“返回()”,此时我不需要使用内联汇编对栈进行平衡,因为这个子程序自己处理了堆栈平衡
4.也就是说ret 代替了 “返回()”

你看看我1-4有没有理解错误的,如果有错误的帮我更正一下


补充内容 (2024-11-8 12:00):
补充:5.图中代码指只是生成一段汇编代码,返回一段字节集,没有通过易语言的子程序下运行,所以不需要平衡 堆栈

点评

是的,第一点的前提是对方也是stdcall。 在易语言的子程序内用ret汇编指令等效返回,要负责堆栈的平衡。如果这个子程序没有参数,就是直接ret   福建省福州市  发表于 2024-11-8 12:04
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 致发广告者

发布主题 收藏帖子 返回列表

sitemap| 易语言源码| 易语言教程| 易语言论坛| 易语言模块| 手机版| 广告投放| 精易论坛
拒绝任何人以任何形式在本论坛发表与中华人民共和国法律相抵触的言论,本站内容均为会员发表,并不代表精易立场!
论坛帖子内容仅用于技术交流学习和研究的目的,严禁用于非法目的,否则造成一切后果自负!如帖子内容侵害到你的权益,请联系我们!
防范网络诈骗,远离网络犯罪 违法和不良信息举报电话0663-3422125,QQ: 793400750,邮箱:wp@125.la
Powered by Discuz! X3.4 揭阳市揭东区精易科技有限公司 ( 粤ICP备12094385号-1) 粤公网安备 44522102000125 增值电信业务经营许可证 粤B2-20192173

快速回复 返回顶部 返回列表