标题:有关子程序参数传递和堆栈平衡问题
只看楼主
tigerdown
Rank: 1
等 级:新手上路
帖 子:63
专家分:3
注 册:2017-8-21
结帖率:69.23%
已结贴  问题点数:20 回复次数:6 
有关子程序参数传递和堆栈平衡问题
有关子程序参数传递和堆栈平衡问题
发现网上一些资料对这问题解答不十分正确,所以有必要跟大家讨论一下,欢迎提意见。
子程序参数的传递是通过堆栈进行的,就是把子程序的参数压入堆栈,然后子程序在堆栈取出,比如下面例子:

Sub(Var1, Var2)  - StdCall类型

编译后:

push Var2  (待定)
push Var1  (待定)
call Sub

但是参数压入堆栈顺序是如何的呢?是Var2还是Var1先压入?看下面例子和图示:
Sub proc _Var1, _Var2
    mov  eax, _Var1
    mov  ebx, _Var2
    ret
Sub endp

反汇编后:

:00401018 55          push ebp  -  保存ebp指针
:00401019 8BEC        mov  ebp, esp  -  esp指向这里
:0040101B 8B4508      mov  eax, dword ptr[ebp+08] - Var1
:0040101E 8B5D0C      mov  ebx, dword ptr[ebp+0C] - Var2   
:00401021 C9          leave
:00401022 C20800      ret 0008 - 堆栈平衡:esp+0008 = ebp


可以看出Var2地址大于Var1, 所以Var2先入。完成调用后,要清除堆栈空间,由子程序用ret 0008来实现。


[此贴子已经被作者于2020-9-3 17:46编辑过]

搜索更多相关主题的帖子: 平衡 堆栈 参数 子程序 mov 
2020-09-03 17:44
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:11
帖 子:337
专家分:2462
注 册:2016-5-15
得分:20 
stdcall 就是由右到左压栈,退出时由子程式清除堆栈,这些在高阶语言都由编译器处理

其实masm也会这一套,例如

invoke MyProgram,val1,val2,val3

编译器也是用 stdcall方式, 由右到左压栈,而子程序的参数框架,清空堆栈等工作都由汇编器包办

程序代码:

MyProgram proc near data1:WORD, data2:WORD, data3:WORD 
    push bp        ;由汇编器填写
    mov bp,sp    ;由汇编器填写
    mov ax,data1    ;子程序代码开始
    mov bx,data2
    ...        
    ...
    ...
    mov sp,bp    ;由汇编器填写
    pop bp        ;由汇编器填写
    ret 0006    ;程式只须写ret, ret 0006由汇编器计算并代补完

MyProgram endp 
2020-09-03 19:56
tigerdown
Rank: 1
等 级:新手上路
帖 子:63
专家分:3
注 册:2017-8-21
得分:0 
回复 2楼 Valenciax
我有一个疑问,有的堆栈是从低地址向高地址生长的(有可能是不同处理器),在这种情况下是不是也是Var2先压入?
2020-09-03 20:08
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:11
帖 子:337
专家分:2462
注 册:2016-5-15
得分:0 
这是win16遗留下来的参数传递方式,有两种 C 和 PASCAL。

C 规定参数传递顺序是从右到左,即最右边的参数最先压栈,由调用者恢复堆栈指针。编译后就是
push xx
push yy
call zzz
add sp,4

PASCAL约定和C约定正好相反,它规定参数是从左向右传递,由被调用者恢复堆栈。也就是ret n 由子程序负责.

STDCALL是C约定和PASCAL约定的混合体,它规定参数的传递是从右到左, 恢复堆栈的工作交由被调用者完成。

Win32只用STDCALL约定,至于其他语言,可能有非STDCALL的方式

不管那种方式,程式師通常都不必关心,因为操作栈的细节都由编译器代劳


2020-09-03 20:29
tigerdown
Rank: 1
等 级:新手上路
帖 子:63
专家分:3
注 册:2017-8-21
得分:0 
回复 4楼 Valenciax
多谢了,不过对C类型的调用完后,要加上add esp, 8 指令来清除参数空间.
2020-09-03 21:08
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:11
帖 子:337
专家分:2462
注 册:2016-5-15
得分:0 
回复 5楼 tigerdown
要看参数是word的16bit程式还是dword的32bit.再乘上参数个数来决定要如何调整.
2020-09-03 21:14
tigerdown
Rank: 1
等 级:新手上路
帖 子:63
专家分:3
注 册:2017-8-21
得分:0 
谢了。
2020-09-03 21:16



参与讨论请移步原网站贴子:https://bbs.bccn.net/thread-503058-1-1.html




关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.308791 second(s), 9 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved