首页
社区
课程
招聘
[求助]关于调用约定
发表于: 2009-1-19 22:31 6855

[求助]关于调用约定

2009-1-19 22:31
6855
今天在看一本书上说:“不管程序是用什么语言写的,windows api都是pascal调用约定。因此参数从左到右入栈,最后入栈的是返回地址。”
我的问题是:这句话一定成立吗?

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 0
支持
分享
最新回复 (17)
雪    币: 293
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
我记得好像是Stdcall的调用约定啊?难道我记错了?
等高人来解释吧。

《Windows环境下32位汇编语言》
3.4.2  参数传递和堆栈平衡
Win32约定的类型是StdCall,所以在程序中调用子程序或系统API后,不必自己来平衡堆栈,免去了很多麻烦。
2009-1-19 23:45
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
3
fastcall就不是啊,准确说,不完全是
2009-1-19 23:51
0
雪    币: 217
活跃值: (35)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
pascal就是stdcall,windows api的却全部都是stdcall,crt runtime当然不是。
2009-1-20 03:11
0
雪    币: 249
活跃值: (10)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
5
不知道就不要乱讲,少误人子弟.

windows api的却全部都是stdcall

wsprintf

C SysCall StdCall Basic Fortran Pascal
参数从左到右       是 是 是
参数从右到左 是 是 是      
调用者清除堆栈 是           
允许使用:VARARG 是 是 是
2009-1-20 03:49
0
雪    币: 212
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
回到Win16时代这句话就成立了
2009-1-20 08:35
0
雪    币: 208
活跃值: (14)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
你的意思是:在win16的API都是pascal调用约定的,但是在win32 api 就是stdcall调用约定?
2009-1-20 19:46
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
是stdcall
2009-1-20 22:42
0
雪    币: 212
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
我记得win16就是PASCAL方式调用的,win32一般就是用stdcall了
2009-1-21 13:09
0
雪    币: 8209
活跃值: (4559)
能力值: ( LV15,RANK:2473 )
在线值:
发帖
回帖
粉丝
10
有特例的,比如wsprintf就是_cdecl
2009-1-21 13:41
0
雪    币: 208
活跃值: (14)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
[QUOTE=;]...[/QUOTE]
谢谢楼上各位:
基本上明白了。
在win16的时候,API就是pascal调用。
在win32的时候,API就是stdcall调用。如果是参数未定的,只能用cdecl调用了。
2009-1-21 19:39
0
雪    币: 217
活跃值: (35)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
不知道是你不懂还是我不懂,都说了crt的函数不算。
2009-1-22 00:20
0
雪    币: 249
活跃值: (10)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
13
莫非wsprintf也属crt
2009-1-22 00:33
0
雪    币: 249
活跃值: (10)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
14
DbgPrint
2009-1-22 00:34
0
雪    币: 126
活跃值: (239)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
15
WIN31时代都是真正的Pascal调用约定.
WIN32时代就都是STDCALL了.不过有宏定义PASCAL就是STDCALL.
少数不能确定参数个数和类型的API是C约定的,例如sprintf,dbgprint等
2009-1-23 12:18
0
雪    币: 247
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
.............................
2009-1-23 14:50
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
stdcall 
1 所有参数从右至左进入堆栈
2 断点进入堆栈
3 转调用地址
4 EBP进入堆栈
5 ESP赋予EBP
6 ESP值减少n字节,n根据local 定义的局部变量来确定
7 根据uses来确定需要进入堆栈的寄存器
8 开始执行调用地址的指令
  返回时
1 根据uses来确定需要弹出堆栈的寄存器
2 LEAVE指令,相当于
   EBP赋予ESP(恢复ESP)
   POP EBP(恢复EBP)
  这样就跳过了局部变量
3 ret n (n根据参数长度决定)
  这样在返回后就自动清除掉参数

用一个简单的例子来证明
;(add_1+add_2)异或(add_3+add_4)
.386
.model flat, stdcall
option casemap :none

include    windows.inc
include    user32.inc
includelib  user32.lib
include    kernel32.inc
includelib  kernel32.lib

AddProc    proto stdcall :dword,:dword,:dword,:dword,:dword

.data
add_1  dword 1
add_2  dword 2
add_3  dword 3
add_4  dword 4
add_sum  dword ?

.code
start:
invoke AddProc,add_1,add_2,add_3,add_4,add_sum
invoke ExitProcess,NULL

AddProc    proc stdcall uses esi edi ebx Op_1:dword, Op_2:dword,  Op_3:dword, Op_4:dword, Op_Sum:dword
  
  LOCAL @temp:dword
  
  mov eax,Op_1
  add eax,Op_2
  mov @temp,eax
  mov eax,Op_3
  add eax,Op_4
  xor eax,@temp
  mov Op_Sum,eax
  
  ret

AddProc endp

end  start

代码是这样滴
00401000 >/$  FF35 10304000 PUSH DWORD PTR DS:[403010]               ; /Arg5 = 00000000
00401006  |.  FF35 0C304000 PUSH DWORD PTR DS:[40300C]               ; |Arg4 = 00000004
0040100C  |.  FF35 08304000 PUSH DWORD PTR DS:[403008]               ; |Arg3 = 00000003
00401012  |.  FF35 04304000 PUSH DWORD PTR DS:[403004]               ; |Arg2 = 00000002
00401018  |.  FF35 00304000 PUSH DWORD PTR DS:[403000]               ; |Arg1 = 00000001
0040101E  |.  E8 07000000   CALL temp1.0040102A                      ; \temp1.0040102A
00401023  |.  6A 00         PUSH 0                                   ; /ExitCode = 0
00401025  \.  E8 26000000   CALL <JMP.&kernel32.ExitProcess>         ; \ExitProcess
0040102A  /$  55            PUSH EBP
0040102B  |.  8BEC          MOV EBP,ESP
0040102D  |.  83C4 FC       ADD ESP,-4
00401030  |.  56            PUSH ESI
00401031  |.  57            PUSH EDI
00401032  |.  53            PUSH EBX
00401033  |.  8B45 08       MOV EAX,DWORD PTR SS:[EBP+8]
00401036  |.  0345 0C       ADD EAX,DWORD PTR SS:[EBP+C]
00401039  |.  8945 FC       MOV DWORD PTR SS:[EBP-4],EAX
0040103C  |.  8B45 10       MOV EAX,DWORD PTR SS:[EBP+10]
0040103F  |.  0345 14       ADD EAX,DWORD PTR SS:[EBP+14]
00401042  |.  3345 FC       XOR EAX,DWORD PTR SS:[EBP-4]
00401045  |.  8945 18       MOV DWORD PTR SS:[EBP+18],EAX
00401048  |.  5B            POP EBX
00401049  |.  5F            POP EDI
0040104A  |.  5E            POP ESI
0040104B  |.  C9            LEAVE
0040104C  \.  C2 1400       RETN 14
0040104F      CC            INT3
00401050   .- FF25 00204000 JMP DWORD PTR DS:[<&kernel32.ExitProcess>;  kernel32.ExitProcess
2009-1-23 16:29
0
雪    币: 207
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
Win32的VC里PASCAL是一个宏,实际上还是__stdcall,参数应该从右到左压栈才对。Win16就不太清楚了,可能Win16里pascal参数是从左到右压栈吧。
2009-1-24 16:44
0
游客
登录 | 注册 方可回帖
返回