汇编中参数的传递和堆栈修正

[复制链接]
发表于 2008-9-28 16:22:28 | 显示全部楼层 |阅读模式
&nbsp;&nbsp;在 Win32汇编中,我们经常要和 Api 打交道,另外也会常常使用自己编制的类似于 Api 的带参数的子程序,本文要讲述的是在子程序调用的过程中进行参数传递的概念和分析。一般在程序中,参数的传递是通过堆栈进行的,也就是说,调用者把要传递给子程序(或者被调用者)的参数压入堆栈,子程序在堆栈取出相应的值再使用,比如说,如果你要调用 SubRouting(Var1,Var2,Var3),编译后的最终代码<SPAN style="COLOR: red">可能</SPAN>是<BR><BR>push Var3<BR>push Var2<BR>push Var1<BR>call SubRouting<BR>add esp,12<BR><BR>也就是说,调用者首先把参数压入堆栈,然后调用子程序,在完成后,由于堆栈中先前压入的数不再有用,调用者或者被调用者必须有一方把堆栈指针修正到调用前的状态。参数是最右边的先入堆栈还是最左边的先入堆栈、还有由调用者还是被调用者来修正堆栈都必须有个约定,不然就会产生不正确的结果,这就是我在前面使用“可能”这两个字的原因:各种语言中调用子程序的约定是不同的,它们的不同点见下表:<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p></o:p>& H7 H" @( M% @
<TABLE style="WIDTH: 581.25pt; mso-cellspacing: 0cm; mso-padding-alt: 0cm 0cm 0cm 0cm" cellSpacing=0 borderColorDark=#ffffff cellPadding=0 width=775 borderColorLight=#000000 border=1>
0 |) x- [. h* L. e/ d1 f<TBODY>
" \) S0 l/ t; W% M1 l, V! j5 @( Y<TR>
/ {+ y) C, }; Z* j: O7 |<TD style="PADDING-RIGHT: 0cm; PADDING-LEFT: 0cm; BACKGROUND: #66cccc; PADDING-BOTTOM: 0cm; PADDING-TOP: 0cm">" E. |$ U7 {7 \9 Z. x
<P class=MsoNormal><SPAN lang=EN-US>&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><o:p></o:p></SPAN></P></TD>; L7 @+ Y  e- }
<TD style="PADDING-RIGHT: 0cm; PADDING-LEFT: 0cm; BACKGROUND: #66cccc; PADDING-BOTTOM: 0cm; PADDING-TOP: 0cm">/ z* l0 t: b/ Z
<P class=MsoNormal style="TEXT-ALIGN: center" align=center><SPAN lang=EN-US>C</SPAN><SPAN lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><o:p></o:p></SPAN></P></TD>
7 ~9 z, d0 L, w<TD style="PADDING-RIGHT: 0cm; PADDING-LEFT: 0cm; BACKGROUND: #66cccc; PADDING-BOTTOM: 0cm; PADDING-TOP: 0cm">& H- ]' d& j" {5 e& P' H4 m! O
<P class=MsoNormal style="TEXT-ALIGN: center" align=center><SPAN lang=EN-US>SysCall</SPAN><SPAN lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><o:p></o:p></SPAN></P></TD>+ J; V  R: u# |
<TD style="PADDING-RIGHT: 0cm; PADDING-LEFT: 0cm; BACKGROUND: #66cccc; PADDING-BOTTOM: 0cm; PADDING-TOP: 0cm">
+ L( ^: d1 c9 ]/ a$ b! K<P class=MsoNormal style="TEXT-ALIGN: center" align=center><SPAN lang=EN-US>StdCall</SPAN><SPAN lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><o:p></o:p></SPAN></P></TD>% {. R4 k4 I" `
<TD style="PADDING-RIGHT: 0cm; PADDING-LEFT: 0cm; BACKGROUND: #66cccc; PADDING-BOTTOM: 0cm; PADDING-TOP: 0cm">+ {. f! I: I' O; I' h+ W3 s
<P class=MsoNormal style="TEXT-ALIGN: center" align=center><SPAN lang=EN-US>Basic</SPAN><SPAN lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><o:p></o:p></SPAN></P></TD>
6 f0 S8 _$ M1 W3 [; g( u: b<TD style="PADDING-RIGHT: 0cm; PADDING-LEFT: 0cm; BACKGROUND: #66cccc; PADDING-BOTTOM: 0cm; PADDING-TOP: 0cm">7 i9 o- ?. `6 v( t4 F9 S  \. L
<P class=MsoNormal style="TEXT-ALIGN: center" align=center><SPAN lang=EN-US>Fortran</SPAN><SPAN lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><o:p></o:p></SPAN></P></TD>
  W3 e( F& e( e$ j<TD style="PADDING-RIGHT: 0cm; PADDING-LEFT: 0cm; BACKGROUND: #66cccc; PADDING-BOTTOM: 0cm; PADDING-TOP: 0cm">& B/ |9 `8 K, W* p" J
<P class=MsoNormal style="TEXT-ALIGN: center" align=center><SPAN lang=EN-US>Pascal</SPAN><SPAN lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><o:p></o:p></SPAN></P></TD></TR>
$ |# |4 I3 V+ T5 ~<TR>
8 W  a8 ~& M# Y  r* d* \% p<TD style="PADDING-RIGHT: 0cm; PADDING-LEFT: 0cm; BACKGROUND: #66cccc; PADDING-BOTTOM: 0cm; WIDTH: 28%; PADDING-TOP: 0cm" width="28%">
5 [2 r3 G4 @7 x7 B1 f<P class=MsoNormal><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">参数从左到右</SPAN><SPAN lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><o:p></o:p></SPAN></P></TD>
& V3 m/ k. ]/ [1 Q# ^/ i% d<TD style="PADDING-RIGHT: 0cm; PADDING-LEFT: 0cm; BACKGROUND: #ccccff; PADDING-BOTTOM: 0cm; WIDTH: 12%; PADDING-TOP: 0cm" width="12%">+ @8 |" \* |& N# M- E- U6 i
<P class=MsoNormal style="TEXT-ALIGN: center" align=center><SPAN lang=EN-US>&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><o:p></o:p></SPAN></P></TD>
. x- s! `$ K" d  I8 g3 I# W<TD style="PADDING-RIGHT: 0cm; PADDING-LEFT: 0cm; BACKGROUND: #ccccff; PADDING-BOTTOM: 0cm; WIDTH: 12%; PADDING-TOP: 0cm" width="12%">
0 u$ |- h( K* e0 @% o6 |( p<P class=MsoNormal style="TEXT-ALIGN: center" align=center><SPAN lang=EN-US>&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><o:p></o:p></SPAN></P></TD>
6 \" g* s2 @( e0 ^, V" s* |1 Z<TD style="PADDING-RIGHT: 0cm; PADDING-LEFT: 0cm; BACKGROUND: #ccccff; PADDING-BOTTOM: 0cm; WIDTH: 12%; PADDING-TOP: 0cm" width="12%">  J5 C5 t; @8 i* ]: ~* q
<P class=MsoNormal style="TEXT-ALIGN: center" align=center><SPAN lang=EN-US>&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><o:p></o:p></SPAN></P></TD>
5 {' b* L$ }& R0 A( @% W' w<TD style="PADDING-RIGHT: 0cm; PADDING-LEFT: 0cm; BACKGROUND: #ccccff; PADDING-BOTTOM: 0cm; WIDTH: 12%; PADDING-TOP: 0cm" width="12%">
  \5 g: {  O! r( H3 A  `' h<P class=MsoNormal style="TEXT-ALIGN: center" align=center><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">是</SPAN><SPAN lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><o:p></o:p></SPAN></P></TD>2 P# y- O0 i: O# ?9 q% x
<TD style="PADDING-RIGHT: 0cm; PADDING-LEFT: 0cm; BACKGROUND: #ccccff; PADDING-BOTTOM: 0cm; WIDTH: 12%; PADDING-TOP: 0cm" width="12%">
" Z7 z6 M# i8 u+ `5 W<P class=MsoNormal style="TEXT-ALIGN: center" align=center><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">是</SPAN><SPAN lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><o:p></o:p></SPAN></P></TD>
" u- A3 K: p/ }: n; U* e- M<TD style="PADDING-RIGHT: 0cm; PADDING-LEFT: 0cm; BACKGROUND: #ccccff; PADDING-BOTTOM: 0cm; WIDTH: 12%; PADDING-TOP: 0cm" width="12%">! P+ R% y3 U# G/ y
<P class=MsoNormal style="TEXT-ALIGN: center" align=center><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">是</SPAN><SPAN lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><o:p></o:p></SPAN></P></TD></TR>. {- ?+ J/ k$ N/ v) c
<TR>1 h2 W2 Q6 ^& y- Y* @- y: v" f6 Y
<TD style="PADDING-RIGHT: 0cm; PADDING-LEFT: 0cm; BACKGROUND: #66cccc; PADDING-BOTTOM: 0cm; WIDTH: 28%; PADDING-TOP: 0cm" width="28%">
- C+ ?) c4 d9 g<P class=MsoNormal><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">参数从右到左</SPAN><SPAN lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><o:p></o:p></SPAN></P></TD>. ?9 y/ O  X1 S$ r
<TD style="PADDING-RIGHT: 0cm; PADDING-LEFT: 0cm; BACKGROUND: #ccccff; PADDING-BOTTOM: 0cm; WIDTH: 12%; PADDING-TOP: 0cm" width="12%">5 f3 p8 f- X1 z; I( C7 x) K
<P class=MsoNormal style="TEXT-ALIGN: center" align=center><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">是</SPAN><SPAN lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><o:p></o:p></SPAN></P></TD># ?/ t/ |3 [6 ?/ g& W
<TD style="PADDING-RIGHT: 0cm; PADDING-LEFT: 0cm; BACKGROUND: #ccccff; PADDING-BOTTOM: 0cm; WIDTH: 12%; PADDING-TOP: 0cm" width="12%">' d# q1 R; k$ X, x8 Z8 m5 t- s( x
<P class=MsoNormal style="TEXT-ALIGN: center" align=center><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">是</SPAN><SPAN lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><o:p></o:p></SPAN></P></TD>7 V" i* k# c3 z( D
<TD style="PADDING-RIGHT: 0cm; PADDING-LEFT: 0cm; BACKGROUND: #ccccff; PADDING-BOTTOM: 0cm; WIDTH: 12%; PADDING-TOP: 0cm" width="12%">
# N/ {6 F- {1 `- \, c% S<P class=MsoNormal style="TEXT-ALIGN: center" align=center><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">是</SPAN><SPAN lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><o:p></o:p></SPAN></P></TD>8 i5 Z$ B9 s" ?9 S) G" k9 g+ z
<TD style="PADDING-RIGHT: 0cm; PADDING-LEFT: 0cm; BACKGROUND: #ccccff; PADDING-BOTTOM: 0cm; WIDTH: 12%; PADDING-TOP: 0cm" width="12%">  t& \6 F# w( _( N! |! G
<P class=MsoNormal style="TEXT-ALIGN: center" align=center><SPAN lang=EN-US>&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><o:p></o:p></SPAN></P></TD>. P5 L8 g" S1 i* u/ H1 F6 K: k
<TD style="PADDING-RIGHT: 0cm; PADDING-LEFT: 0cm; BACKGROUND: #ccccff; PADDING-BOTTOM: 0cm; WIDTH: 12%; PADDING-TOP: 0cm" width="12%">* b4 g, z* W9 A7 f9 M
<P class=MsoNormal style="TEXT-ALIGN: center" align=center><SPAN lang=EN-US>&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><o:p></o:p></SPAN></P></TD>; j$ J# a' l9 f- U8 i: i
<TD style="PADDING-RIGHT: 0cm; PADDING-LEFT: 0cm; BACKGROUND: #ccccff; PADDING-BOTTOM: 0cm; WIDTH: 12%; PADDING-TOP: 0cm" width="12%">. D; {2 K& U) ~% D) L6 M
<P class=MsoNormal style="TEXT-ALIGN: center" align=center><SPAN lang=EN-US>&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><o:p></o:p></SPAN></P></TD></TR>6 X( @) P" A$ E, I
<TR>
: s4 D  g' B, W( \<TD style="PADDING-RIGHT: 0cm; PADDING-LEFT: 0cm; BACKGROUND: #66cccc; PADDING-BOTTOM: 0cm; WIDTH: 28%; PADDING-TOP: 0cm" width="28%"># [! m. T- B1 X5 S
<P class=MsoNormal><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">调用者清除堆栈</SPAN><SPAN lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><o:p></o:p></SPAN></P></TD>6 ]3 a- k, \3 a6 m6 X
<TD style="PADDING-RIGHT: 0cm; PADDING-LEFT: 0cm; BACKGROUND: #ccccff; PADDING-BOTTOM: 0cm; WIDTH: 12%; PADDING-TOP: 0cm" width="12%">
* s, W1 o4 J" ]6 a% }( L4 K4 m5 r<P class=MsoNormal style="TEXT-ALIGN: center" align=center><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">是</SPAN><SPAN lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><o:p></o:p></SPAN></P></TD>
3 o* f$ ^. V' z' F<TD style="PADDING-RIGHT: 0cm; PADDING-LEFT: 0cm; BACKGROUND: #ccccff; PADDING-BOTTOM: 0cm; WIDTH: 12%; PADDING-TOP: 0cm" width="12%">" _) i% d( N- _* w: c
<P class=MsoNormal style="TEXT-ALIGN: center" align=center><SPAN lang=EN-US>&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><o:p></o:p></SPAN></P></TD>/ ^9 v; ]% Y" h$ S* L* z3 I
<TD style="PADDING-RIGHT: 0cm; PADDING-LEFT: 0cm; BACKGROUND: #ccccff; PADDING-BOTTOM: 0cm; WIDTH: 12%; PADDING-TOP: 0cm" width="12%">
: N0 B/ N' n+ s( ?6 {* t% D. e- R<P class=MsoNormal style="TEXT-ALIGN: center" align=center><SPAN lang=EN-US>&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><o:p></o:p></SPAN></P></TD>
7 }0 X: H# `" ~: `  U! N<TD style="PADDING-RIGHT: 0cm; PADDING-LEFT: 0cm; BACKGROUND: #ccccff; PADDING-BOTTOM: 0cm; WIDTH: 12%; PADDING-TOP: 0cm" width="12%">$ F" c8 P2 e4 B  G
<P class=MsoNormal style="TEXT-ALIGN: center" align=center><SPAN lang=EN-US>&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><o:p></o:p></SPAN></P></TD>( ?* M% @; ?) ~8 `0 C
<TD style="PADDING-RIGHT: 0cm; PADDING-LEFT: 0cm; BACKGROUND: #ccccff; PADDING-BOTTOM: 0cm; WIDTH: 12%; PADDING-TOP: 0cm" width="12%">. z- x) J7 F" z$ Q/ o6 N" N% H6 k  B
<P class=MsoNormal style="TEXT-ALIGN: center" align=center><SPAN lang=EN-US>&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><o:p></o:p></SPAN></P></TD>% o2 R4 @6 @" M0 [
<TD style="PADDING-RIGHT: 0cm; PADDING-LEFT: 0cm; BACKGROUND: #ccccff; PADDING-BOTTOM: 0cm; WIDTH: 12%; PADDING-TOP: 0cm" width="12%">5 B4 K0 x# r3 ?
<P class=MsoNormal style="TEXT-ALIGN: center" align=center><SPAN lang=EN-US>&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><o:p></o:p></SPAN></P></TD></TR>
& q$ ]) ?1 D' `3 J* H4 i  v<TR>
' O: U+ b0 `0 v, B( M" N" V( S- T<TD style="PADDING-RIGHT: 0cm; PADDING-LEFT: 0cm; BACKGROUND: #66cccc; PADDING-BOTTOM: 0cm; WIDTH: 28%; PADDING-TOP: 0cm" width="28%">
  O. D  W; r- X<P class=MsoNormal><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">允许使用</SPAN><SPAN lang=EN-US>:VARARG</SPAN><SPAN lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><o:p></o:p></SPAN></P></TD>) i1 A1 w8 d8 ?+ X
<TD style="PADDING-RIGHT: 0cm; PADDING-LEFT: 0cm; BACKGROUND: #ccccff; PADDING-BOTTOM: 0cm; WIDTH: 12%; PADDING-TOP: 0cm" width="12%">
/ I0 E. _( A5 m' g; u<P class=MsoNormal style="TEXT-ALIGN: center" align=center><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">是</SPAN><SPAN lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><o:p></o:p></SPAN></P></TD>
8 `% U2 \% o4 d$ j5 C1 {<TD style="PADDING-RIGHT: 0cm; PADDING-LEFT: 0cm; BACKGROUND: #ccccff; PADDING-BOTTOM: 0cm; WIDTH: 12%; PADDING-TOP: 0cm" width="12%">  R4 T2 k1 x5 ?* G3 Q' h% e4 f0 F& g
<P class=MsoNormal style="TEXT-ALIGN: center" align=center><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">是</SPAN><SPAN lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><o:p></o:p></SPAN></P></TD>5 k8 z) A) a$ r; w( p
<TD style="PADDING-RIGHT: 0cm; PADDING-LEFT: 0cm; BACKGROUND: #ccccff; PADDING-BOTTOM: 0cm; WIDTH: 12%; PADDING-TOP: 0cm" width="12%">0 g, u2 E3 y5 r
<P class=MsoNormal style="TEXT-ALIGN: center" align=center><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">是</SPAN><SPAN lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><o:p></o:p></SPAN></P></TD>
2 [) r7 V0 q% |2 T$ D# x: J<TD style="PADDING-RIGHT: 0cm; PADDING-LEFT: 0cm; BACKGROUND: #ccccff; PADDING-BOTTOM: 0cm; WIDTH: 12%; PADDING-TOP: 0cm" width="12%">
3 T6 B' E3 R, y4 a$ L; B<P class=MsoNormal style="TEXT-ALIGN: center" align=center><SPAN lang=EN-US>&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><o:p></o:p></SPAN></P></TD>
" M- B/ J7 e& q- X1 J% g- t<TD style="PADDING-RIGHT: 0cm; PADDING-LEFT: 0cm; BACKGROUND: #ccccff; PADDING-BOTTOM: 0cm; WIDTH: 12%; PADDING-TOP: 0cm" width="12%">
# u3 _/ T4 M6 r<P class=MsoNormal style="TEXT-ALIGN: center" align=center><SPAN lang=EN-US>&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><o:p></o:p></SPAN></P></TD>5 w" t, x/ v: E6 k& x/ v( U! l) l- }0 g
<TD style="PADDING-RIGHT: 0cm; PADDING-LEFT: 0cm; BACKGROUND: #ccccff; PADDING-BOTTOM: 0cm; WIDTH: 12%; PADDING-TOP: 0cm" width="12%">
. Q+ _' v7 q# e5 ~7 Z# ]<P class=MsoNormal style="TEXT-ALIGN: center" align=center><SPAN lang=EN-US>&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><o:p></o:p></SPAN></P></TD></TR></TBODY></TABLE>4 ?" o3 \7 c4 D) R5 b
<P><SPAN lang=EN-US>VARARG 表示参数的个数可以是不确定的,有一个例子就是 C 中的 printf 语句,在上表中,StdCall 的定义有个要说明的地方,就是如果 StdCall 使用 :VARARG 时,是由调用者清除堆栈的,而在没有:VARARG时是由被调用者清除堆栈的。<BR>在 Win32 汇编中,约定使用 StdCall 方式,所以我们要在程序开始的时候使用 .model stdcall 语句。也就是说,在 API 或子程序中,最右边的参数先入堆栈,然后子程序在返回的时候负责校正堆栈,举例说明,如果我们要调用 MessageBox 这个 API,因为它的定义是 MessageBox(hWnd,lpText,lpCaption,UType) 所以在程序中要这样使用:<o:p></o:p></SPAN></P>
% q) U3 c6 N0 L<P><SPAN lang=EN-US>push MB_OK<BR>push offset szCaption<BR>push offset szText<BR>push hWnd<BR>call MessageBox<BR>...<o:p></o:p></SPAN></P>! z; h+ v' u% `. W: V
<P>我们不必在<SPAN lang=EN-US> API 返回的时候加上一句 add sp,4*4 来修正堆栈,因为这已经由 MessageBox 这个子程序做了。在 Windows API 中,唯一一个特殊的 API 是 wsprintf,这个 API 是 C 约定的,它的定义是 wsprintf(lpOut,lpFormat,Var1,Var2...),所以在使用时就要:<o:p></o:p></SPAN></P>& s& g) w$ ~0 o# l3 }7 |. H
<P><SPAN lang=EN-US>push 1111<BR>push 2222<BR>push 3333<BR>push offset szFormat<BR>push offset szOut<BR>call wsprintf<BR>add esp,4*5</SPAN></P>
  t& x5 u5 d! ]1 y<P><SPAN lang=EN-US>&nbsp;<o:p></o:p></SPAN></P>
* N; P6 u! s! q  K- |<P><SPAN lang=EN-US>&nbsp;<o:p></o:p></SPAN></P>9 ?/ _0 p" u. Z; C2 @# R" n" c4 t
<P><SPAN lang=EN-US>&nbsp;<o:p></o:p></SPAN></P>
7 ^! s$ z! D5 N0 q& }; s% M<P><SPAN lang=EN-US>&nbsp;<o:p></o:p></SPAN></P>
! r5 o% D6 p( X. p. U) @<P><SPAN lang=EN-US>&nbsp;<o:p></o:p></SPAN></P>$ e+ y) z7 [  t! ]7 Y9 b
<P><?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" /><v:shapetype id=_x0000_t75 stroked="f" filled="f" path=" m@4@5 l@4@11@9@11@9@5 xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0 "></v:f><v:f eqn="sum @0 1 0 "></v:f><v:f eqn="sum 0 0 @1 "></v:f><v:f eqn="prod @2 1 2 "></v:f><v:f eqn="prod @3 21600 pixelWidth "></v:f><v:f eqn="prod @3 21600 pixelHeight "></v:f><v:f eqn="sum @0 0 1 "></v:f><v:f eqn="prod @6 1 2 "></v:f><v:f eqn="prod @7 21600 pixelWidth "></v:f><v:f eqn="sum @8 21600 0 "></v:f><v:f eqn="prod @7 21600 pixelHeight "></v:f><v:f eqn="sum @10 21600 0 "></v:f></v:formulas><v:path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></v:path><o:lock aspectratio="t" v:ext="edit"></o:lock></v:shapetype><v:shape id=_x0000_s1026 style="MARGIN-TOP: 0px; Z-INDEX: 1; MARGIN-LEFT: 130.25pt; WIDTH: 170.25pt; POSITION: absolute; HEIGHT: 180pt; mso-wrap-distance-left: 3.75pt; mso-wrap-distance-top: 3.75pt; mso-wrap-distance-right: 3.75pt; mso-wrap-distance-bottom: 3.75pt; mso-position-horizontal: right; mso-position-horizontal-relative: text; mso-position-vertical-relative: line" alt="" coordsize="21600,21600" type="#_x0000_t75" o:allowoverlap="f"><?xml:namespace prefix = w ns = "urn:schemas-microsoft-com:office:word" /><w:wrap type="square"></w:wrap></v:shape>下面要讲的是子程序如何存取参数,因为缺省对堆栈操作的寄存器有<SPAN lang=EN-US> 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],下面是一个典型的子程序,可以完成第一个参数减去第二个参数,它的定义是:<BR><BR>MyProc proto Var1,Var2 ;有两个参数<BR>local lVar1,lVar2 ;有两个局部变量<o:p></o:p></SPAN></P>9 _6 Z3 Q/ `3 h, H) q' k$ y; u
<P>注意,这里的两个<SPAN lang=EN-US> local 变量实际上没有被用到,只是为了演示用,具体实现的代码是:<BR><BR>MyProc proc<BR><BR>push ebp<BR>mov ebp,esp<o:p></o:p></SPAN></P>4 }# ~6 ^* V* l8 v+ L' W. J3 O
<P><SPAN lang=EN-US>sub esp,8<o:p></o:p></SPAN></P>
* u* h! X  T$ j( d& R" U9 E<P><SPAN lang=EN-US>mov eax,dword ptr [ebp + 8]<BR>sub eax,dword ptr [ebp + c]<o:p></o:p></SPAN></P>
$ [) @; P# i0 N  \. W<P><SPAN lang=EN-US>add esp,8<o:p></o:p></SPAN></P>
; z4 ~5 V+ f2 D4 F<P><SPAN lang=EN-US>pop ebp<BR>ret 8<o:p></o:p></SPAN></P>
( J9 r& c' C# A. M9 I9 V8 T) M<P><SPAN lang=EN-US>MyProc endp<BR><BR>现在对这个子程序分析一下,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 的功能,所以上面的程序可以改成:<o:p></o:p></SPAN></P>, m. S- k# J* ~) ^% e) t& q/ Q; R
<P><SPAN lang=EN-US>MyPorc proc<BR>enter 8,0<BR><BR>mov eax,dword ptr [ebp + 8]<BR>sub eax,dword ptr [ebp + c]<BR><BR>leave<BR>ret 8<BR>MyProc endp<o:p></o:p></SPAN></P>
$ {, ~4 y) I2 ^7 A<P>好了,说到这儿,参数传递的原理也应该将清楚了,还要最后说的是,在使用<SPAN lang=EN-US> Masm32 编 Win32 汇编程序的时候,我们并不需要记住 [ebp + xx] 等麻烦的地址,或自己计算局部变量需要预留的堆栈空间,还有在 ret 时计算要加上的数值,Masm32 的宏指令都已经把这些做好了,如在 Masm32 中,上面的程序只要写成为:<o:p></o:p></SPAN></P>; q$ `# P% F: @% T: q
<P><SPAN lang=EN-US>MyProc proc Var1,Var2<BR>local lVar1,lVar2<o:p></o:p></SPAN></P>4 ~. J$ k$ Q, L( Z& J5 m
<P><SPAN lang=EN-US>mov eax,Var1<BR>sub eax,Var2<BR>ret<o:p></o:p></SPAN></P>
) n# W8 g4 c4 r: \& K% _<P><SPAN lang=EN-US>MyProc endp<o:p></o:p></SPAN></P>6 g2 g( l  R) i' h: V
<P>编译器会自动的在<SPAN lang=EN-US> mov eax,Var1 前面插上一句 Enter 语句,它的参数会根据 local 定义的局部变量的多少自动指定,在 ret 前会自动加上一句 Leave,同样,编译器会根据参数的多少把 ret 替换成 ret xxx,把 mov eax,Var1 换成 mov eax,dword ptr [ebp + 8] 等等。<o:p></o:p></SPAN></P>
# n5 p) T9 a5 x4 e8 x<P>最后是使用<SPAN lang=EN-US> Masm32 的 invoke 宏指令,在前面可以看到,调用带参数的子程序时,我们需要用 push 把参数压入堆栈,如果不小心把参数个数搞错了,就会使堆栈不平衡,从而使程序从堆栈中取出错误的返回地址引起不可预料的后果,所以有必要有一条语句来完成自动检验的任务,invoke 就是这样的语句,实际上,它是自动 push 所有参数,检测参数个数、类型是否正确,并使用 call 来调用的一个宏指令,对于上面的 push/push/call MyProc 的指令,可以用一条指令完成就是:<o:p></o:p></SPAN></P>9 f( J( Q% j1 c9 e& N
<P><SPAN lang=EN-US>invoke MyProc,Var1,Var2<o:p></o:p></SPAN></P>
- u& c5 f; Y# e' e- K4 v. a<P>当然,当程序编译好以后你去看机器码会发现它被正确地换成了同样的<SPAN lang=EN-US> push/push/call 指令。但是,在使用 invoke 之前,为了让它进行正确的参数检验,你需要对函数进行申明,就象在 C 中一样,申明的语句是:<o:p></o:p></SPAN></P>
( W1 k- ~0 Y0 _$ K<P><SPAN lang=EN-US>MyProc proto :DWORD,:DWORD<o:p></o:p></SPAN></P>+ Q" ~) e- E' Y; |9 l, ?  m8 H
<P>语句中<SPAN lang=EN-US> proto 是关键字,表示申明,:DWORD 表示参数的类型是 double word 类型的,有几个就表示有几个参数,在 Win32 中参数都是 double word 型的,申明语句要写在 invoke 之前,所以我们一般把它包括在 include 文件中,好了,综合一下,在 Masm32 中使用一个带参数的子程序或者 Api ,我们只需用:<o:p></o:p></SPAN></P>
- {) f: _' Y& q; [2 c6 L$ j. j+ w<P><SPAN lang=EN-US>...<BR>MyProc proto :dword,:dword<BR>... <BR>.data<BR>x dd ?<BR>y dd ?<BR>dwResult dd ?<BR>...<BR>mov x,1<BR>mov y,2<BR>invoke MyProc x,y<BR>mov dwResult,eax<BR>... <o:p></o:p></SPAN></P>
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关注公众号

相关侵权、举报、投诉及建议等,请发 E-mail:admin@discuz.vip

Powered by Discuz! X5.0 © 2001-2026 Discuz! Team.|鲁ICP备19052200号-1

在本版发帖
关注公众号
QQ客服返回顶部