📄 atl under the hood - part 4.mht
字号:
the same name and tells the compiler to not decorate its name i.e. =
use C=20
language linkage not C++ linkage. </P>
<P>Now take a look what code compiler is generated for our do =
noting=20
function. Here is the code which compiler generate for our =
function. </P><PRE lang=3Dasm> <SPAN class=3Dcpp-keyword>push</SPAN> ebp
<SPAN class=3Dcpp-keyword>mov</SPAN> ebp, esp
<SPAN class=3Dcpp-keyword>pop</SPAN> ebp
<SPAN class=3Dcpp-keyword>ret</SPAN> <SPAN class=3Dcpp-literal>0</SPAN>
</PRE>
<P>Before go into further detail take a look at the last statement =
of the=20
function i.e. ret 0. Why it is 0? Or can it be other than 0? As we =
have=20
seen all the parameters which we pass to the function are in fact =
pushed=20
into the stack. What will be the effect on register when you or =
compiler=20
pushes something on stack? Take a look at the following simple =
program to=20
see the behavior of this. I use the <CODE>printf</CODE> rather =
than=20
<CODE>cout</CODE> to avoid the overhead of <CODE>cout</CODE>.=20
</P><B>Program 59</B> <PRE><SPAN class=3Dcpp-preprocessor>#include =
<cstdio></SPAN>
<SPAN class=3Dcpp-keyword>int</SPAN> g_iTemp;
<SPAN class=3Dcpp-keyword>int</SPAN> main() {
fun(<SPAN class=3Dcpp-literal>5</SPAN>, <SPAN =
class=3Dcpp-literal>10</SPAN>);
<SPAN class=3Dcpp-keyword>_asm</SPAN> mov g_iTemp, esp
printf(<SPAN class=3Dcpp-string>"Before push %d\n"</SPAN>, g_iTemp);
<SPAN class=3Dcpp-keyword>_asm</SPAN> push eax
<SPAN class=3Dcpp-keyword>_asm</SPAN> mov g_iTemp, esp
printf(<SPAN class=3Dcpp-string>"After push %d\n"</SPAN>, g_iTemp);
<SPAN class=3Dcpp-keyword>_asm</SPAN> pop eax
<SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>0</SPAN>;
}
</PRE>
<P>The output of this program is </P><PRE lang=3Dtext>Before push =
1244980
After push 1244976
</PRE>
<P>This program displays the value of ESP register before and =
after push=20
some value into the stack. This clearly shows that when you push =
something=20
into the stack then it grows downward in the memory. </P>
<CENTER><IMG height=3D506=20
=
src=3D"http://www.codeproject.com/atl/atl_underthehood_4/PIC4-1.GIF"=20
width=3D338></CENTER>
<P>Now there is a question, who is goring to restore the stack =
pointer=20
when we pass parameter into the function, the function itself or =
the=20
caller of that function? In fact both cases are possible and this =
is the=20
difference between standard calling convention and c calling =
convention.=20
Take a look at the very next statement after calling the function. =
</P><PRE lang=3Dasm> <SPAN class=3Dcpp-keyword>push</SPAN> <SPAN =
class=3Dcpp-literal>10</SPAN> <SPAN class=3Dcpp-comment>; =
0000000aH</SPAN>
<SPAN class=3Dcpp-keyword>push</SPAN> <SPAN =
class=3Dcpp-literal>5</SPAN>
<SPAN class=3Dcpp-keyword>call</SPAN> _fun
<SPAN class=3Dcpp-keyword>add</SPAN> esp, <SPAN =
class=3Dcpp-literal>8</SPAN>
</PRE>
<P>Here two parameters are passed in the function, so the stack =
pointer is=20
subtract 8 bytes after pushing two values into the stack. Now in =
this=20
program it is the responsibility of the caller of the function to =
set the=20
stack pointer. This is called C Calling convention. In this =
calling=20
convention you can pass variable no of argument, because caller =
knows how=20
many parameter is being passed to the function, so it can set the =
stack=20
pointer itself. </P>
<P>However if standard calling convention is selected then it is =
the=20
responsibility of the callee to clear the stack. So in this case =
variable=20
not of argument can't be passed in the function, because there is =
no way=20
to know the function that how much parameter is passed, so it cal =
set the=20
stack pointer appropriately. </P>
<P>Take a look at the following program to see the behavior of =
standard=20
calling convention. </P><B>Program 60</B> <PRE><SPAN =
class=3Dcpp-keyword>extern</SPAN> <SPAN class=3Dcpp-string>"C"</SPAN> =
<SPAN class=3Dcpp-keyword>void</SPAN> _stdcall fun(<SPAN =
class=3Dcpp-keyword>int</SPAN>, <SPAN class=3Dcpp-keyword>int</SPAN>) {
}
<SPAN class=3Dcpp-keyword>int</SPAN> main() {
fun(<SPAN class=3Dcpp-literal>5</SPAN>, <SPAN =
class=3Dcpp-literal>10</SPAN>);
<SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>0</SPAN>;
}
</PRE>
<P>Now take a look at the calling of function. </P><PRE =
lang=3Dasm> <SPAN class=3Dcpp-keyword>push</SPAN> <SPAN =
class=3Dcpp-literal>10</SPAN> <SPAN class=3Dcpp-comment>; =
0000000aH</SPAN>
<SPAN class=3Dcpp-keyword>push</SPAN> <SPAN =
class=3Dcpp-literal>5</SPAN>
<SPAN class=3Dcpp-keyword>call</SPAN> _fun@<SPAN =
class=3Dcpp-literal>8</SPAN>
</PRE>
<P>Here @ with the function name shows that this is standard =
calling=20
convention and 8 show the no of bytes pushed into the stack. So no =
of=20
argument can be calculated by dividing this no by 4. </P>
<P>Here is the code of our do nothing function </P><PRE =
lang=3Dasm> <SPAN class=3Dcpp-keyword>push</SPAN> ebp
<SPAN class=3Dcpp-keyword>mov</SPAN> ebp, esp
<SPAN class=3Dcpp-keyword>pop</SPAN> ebp
<SPAN class=3Dcpp-keyword>ret</SPAN> <SPAN class=3Dcpp-literal>8</SPAN>
</PRE>
<P>This function set the stack pointer itself with the help of =
"ret 8"=20
instruction before leaving it. </P>
<P>Now explore the code which compiler generate for us. Compiler =
inserts=20
this code to make stack frame so it can access the parameter and =
local=20
variable in standard way. Stack frame is a memory area reserved =
for the=20
function to store the information about the parameter, local =
variable and=20
return address. Stack frame is always created when new function is =
called=20
and destroys when function returns. On 8086 architecture =
<CODE>EBP</CODE>=20
register is used to store the address of stack frame, sometimes =
called=20
stack pointer. </P>
<P>So compiler first save the address of previous stack frame and =
then=20
create new stack frame by using the value of <CODE>ESP</CODE>. And =
before=20
return the function the value of old stack frame is preserved. =
</P>
<P>Now take a look what is in the stack frame. Stack frame have =
all the=20
parameter at +ve side of <CODE>EBP</CODE> and all the local =
variable at=20
-ve side of <CODE>EBP</CODE>. </P>
<P>So the return address of function is store at <CODE>EBP</CODE> =
and the=20
value of previous Stack frame is store at <CODE>EBP + <SPAN=20
class=3Dcpp-literal>4</SPAN>.</CODE> Now take a look at the =
example, which=20
have two parameter and three local variables. </P><B>Program =
61</B> <PRE><SPAN class=3Dcpp-keyword>extern</SPAN> <SPAN =
class=3Dcpp-string>"C"</SPAN> <SPAN class=3Dcpp-keyword>void</SPAN> =
fun(<SPAN class=3Dcpp-keyword>int</SPAN> a, <SPAN =
class=3Dcpp-keyword>int</SPAN> b) {
<SPAN class=3Dcpp-keyword>int</SPAN> x =3D a;
<SPAN class=3Dcpp-keyword>int</SPAN> y =3D b;
<SPAN class=3Dcpp-keyword>int</SPAN> z =3D x + y;
<SPAN class=3Dcpp-keyword>return</SPAN>;
}
<SPAN class=3Dcpp-keyword>int</SPAN> main() {
fun(<SPAN class=3Dcpp-literal>5</SPAN>, <SPAN =
class=3Dcpp-literal>10</SPAN>);
<SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>0</SPAN>;
}
</PRE>
<P>And now take a look at the compiler generated code of the =
function.=20
</P><PRE lang=3Dasm> <SPAN class=3Dcpp-keyword>push</SPAN> ebp
<SPAN class=3Dcpp-keyword>mov</SPAN> ebp, esp
<SPAN class=3Dcpp-keyword>sub</SPAN> esp, <SPAN =
class=3Dcpp-literal>12</SPAN> <SPAN class=3Dcpp-comment>; =
0000000cH</SPAN>
<SPAN class=3Dcpp-comment>; int x =3D a;</SPAN>
<SPAN class=3Dcpp-keyword>mov</SPAN> eax, DWORD PTR _a$[ebp]
<SPAN class=3Dcpp-keyword>mov</SPAN> DWORD PTR _x$[ebp], eax
<SPAN class=3Dcpp-comment>; int y =3D b;</SPAN>
<SPAN class=3Dcpp-keyword>mov</SPAN> ecx, DWORD PTR _b$[ebp]
<SPAN class=3Dcpp-keyword>mov</SPAN> DWORD PTR _y$[ebp], ecx
<SPAN class=3Dcpp-comment>; int z =3D x + y;</SPAN>
<SPAN class=3Dcpp-keyword>mov</SPAN> edx, DWORD PTR _x$[ebp]
<SPAN class=3Dcpp-keyword>add</SPAN> edx, DWORD PTR _y$[ebp]
<SPAN class=3Dcpp-keyword>mov</SPAN> DWORD PTR _z$[ebp], edx
<SPAN class=3Dcpp-keyword>mov</SPAN> esp, ebp
<SPAN class=3Dcpp-keyword>pop</SPAN> ebp
<SPAN class=3Dcpp-keyword>ret</SPAN> <SPAN class=3Dcpp-literal>0</SPAN>
</PRE>
<P>Now what is _x, _y etc. It is define just above the function =
definition=20
something like this </P><PRE lang=3Dtext>_a$ =3D 8
_b$ =3D 12
_x$ =3D -4
_y$ =3D -8
_z$ =3D -12
</PRE>
<P>Means you can read this code something like this </P><PRE =
lang=3Dasm> <SPAN class=3Dcpp-comment>; int x =3D a;</SPAN>
<SPAN class=3Dcpp-keyword>mov</SPAN> eax, DWORD PTR [ebp + <SPAN =
class=3Dcpp-literal>8</SPAN>]
<SPAN class=3Dcpp-keyword>mov</SPAN> DWORD PTR [ebp - <SPAN =
class=3Dcpp-literal>4</SPAN>], eax
<SPAN class=3Dcpp-comment>; int y =3D b;</SPAN>
<SPAN class=3Dcpp-keyword>mov</SPAN> ecx, DWORD PTR [ebp + <SPAN =
class=3Dcpp-literal>12</SPAN>]
<SPAN class=3Dcpp-keyword>mov</SPAN> DWORD PTR [ebp - <SPAN =
class=3Dcpp-literal>8</SPAN>], ecx
<SPAN class=3Dcpp-comment>; int z =3D x + y;</SPAN>
<SPAN class=3Dcpp-keyword>mov</SPAN> edx, DWORD PTR [ebp - <SPAN =
class=3Dcpp-literal>4</SPAN>]
<SPAN class=3Dcpp-keyword>add</SPAN> edx, DWORD PTR [ebp - <SPAN =
class=3Dcpp-literal>8</SPAN>]
<SPAN class=3Dcpp-keyword>mov</SPAN> DWORD PTR [ebp - <SPAN =
class=3Dcpp-literal>12</SPAN>], edx
</PRE>
<P>Means the address of parameters a and b are <CODE>EBP + <SPAN=20
class=3Dcpp-literal>8</SPAN></CODE> and <CODE>EBP + <SPAN=20
class=3Dcpp-literal>12</SPAN> </CODE>respectively. And the value =
of x, y and=20
z are store at memory location <CODE>EBP - <SPAN=20
class=3Dcpp-literal>4</SPAN></CODE>, <CODE>EBP - <SPAN=20
class=3Dcpp-literal>8</SPAN></CODE>, <CODE>EBP - <SPAN=20
class=3Dcpp-literal>12</SPAN> </CODE>respectively. </P>
<P>After armed with this knowledge lets play a game with the =
parameter of=20
the functions. Let's take a look at this simple program. =
</P><B>Program=20
62</B> <PRE><SPAN class=3Dcpp-preprocessor>#include =
<cstdio></SPAN>
<SPAN class=3Dcpp-keyword>extern</SPAN> <SPAN =
class=3Dcpp-string>"C"</SPAN> <SPAN class=3Dcpp-keyword>int</SPAN> =
fun(<SPAN class=3Dcpp-keyword>int</SPAN> a, <SPAN =
class=3Dcpp-keyword>int</SPAN> b) {
<SPAN class=3Dcpp-keyword>return</SPAN> a + b;
}
<SPAN class=3Dcpp-keyword>int</SPAN> main() {
printf(<SPAN class=3Dcpp-string>"%d\n"</SPAN>, fun(<SPAN =
class=3Dcpp-literal>4</SPAN>, <SPAN class=3Dcpp-literal>5</SPAN>));
<SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>0</SPAN>;
}
</PRE>
<P>The output of this program is expected. Out put of this program =
is "9".=20
Now change a program little bit. </P><B>Program 63</B> <PRE><SPAN =
class=3Dcpp-preprocessor>#include <cstdio></SPAN>
<SPAN class=3Dcpp-keyword>extern</SPAN> <SPAN =
class=3Dcpp-string>"C"</SPAN> <SPAN class=3Dcpp-keyword>int</SPAN> =
fun(<SPAN class=3Dcpp-keyword>int</SPAN> a, <SPAN =
class=3Dcpp-keyword>int</SPAN> b) {
<SPAN class=3Dcpp-keyword>_asm</SPAN> mov dword ptr[ebp+<SPAN =
class=3Dcpp-literal>12</SPAN>], <SPAN class=3Dcpp-literal>15</SPAN>
<SPAN class=3Dcpp-keyword>_asm</SPAN> mov dword ptr[ebp+<SPAN =
class=3Dcpp-literal>8</SPAN>], <SPAN class=3Dcpp-literal>14</SPAN>
<SPAN class=3Dcpp-keyword>return</SPAN> a + b;
}
<SPAN class=3Dcpp-keyword>int</SPAN> main() {
printf(<SPAN class=3Dcpp-string>"%d\n"</SPAN>, fun(<SPAN =
class=3Dcpp-literal>4</SPAN>, <SPAN class=3Dcpp-literal>5</SPAN>));
<SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>0</SPAN>;
}
</PRE>
<P>The output of this program is "29". We know the address of =
parameter=20
and in this program we change the value of parameter. And when we =
add=20
those variables then new values i.e. 15 and 14 are added. </P>
<P>VC has naked attributed for function. If you specify any =
function to=20
naked then it won't generate prolog and epilog code for that =
function. Now=20
what is prolog and epilog code? Prolog is an English word mean =
"Opening",=20
yes it is a name of programming language too, which is used in AI, =
but=20
there is no relation between that programming language and prolog =
code=20
generated by the compiler. This is a code which compiler =
automatically=20
inserted in the opening of the function calling to set the stack =
frame.=20
Take a look at assembly language code generated by program 61. In =
the=20
beginning of the function compiler automatically insert the =
following code=20
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -