Connect to the above: http://blog.csdn.net/prsniper/article/details/40652451
The address of the local variable mentioned above, the first one is [ebp-4], because of the 32-bit memory alignment reason, the second is [ebp-8], for VC7 above the version, this address may be different
For example, the first may be [ebp-8], the second fly to [ebp-14], which is vs.net VC compiler before and after each local variable plus a DWORD, the value is naturally 0xCCCCCCCC
Debug if the function ends, these DWORD values are not 0xCCCCCCCC then the code unexpectedly accesses the place that should not be visited, that is, overflow
Below we go to the function that has the return value of the default __CDECL convention to look at:
122: ret = Fndefaultcall (4, 5, 6, &var1); 0040136B Lea eax,[ebp-14h]0040136e Push eax0040136f push 600401371 push 500401373 push 400401375 call @ILT +0 ( Fndefaultcall) (00401005) 0040137A add esp,10h0040137d mov dword ptr [ebp-18h],eax123:
With the knowledge of the preceding, the invocation is simple, and the address is loaded into the Eax,push to the stack, etc.
This eax to the address of the RET, this is not the variable is not initialized to use it? or EAX is the address of RET is ebp-14, what is this?
Yuan Fang said that the VC function uses EAX and edx as the return value! If you had said so earlier, I would have known ...
We're going to go in there and see what it's doing, and the key is in these places.
p = (int *) arg4;004011cc mov eax,dword ptr [ebp+14h]004011cf mov dword ptr [ebp-10h],eax32: *p = 7;004011d2 mov ecx,dword ptr [ebp-10h]004011d5 mov dword ptr [ecx],733:34: return 0;0 04011DB xor eax,eax35: }004011dd pop EDI
The first pass in the DWORD is a pointer, assembly language all over the sky are pointers, compared to high-level language pointers are much less, VB and so simply there is no pointer to the concept,
C + + can be compatible with most of the assembly language functions, cast, then the next assignment is good understanding, *p = 7 is
The value of move p to ecx, and then mov 7 to [ECX] is the memory address that ecx points to
If it is * (int *) ARG4 = 7 is mov ecx, [ebp+14h] again mov [ECX], 7, note if it is ARG4 =7 that is not the same as the value of the modified address is 7, instead of a value of 7
The return 0 is the XOR eax, and any number XOR itself becomes 0,EAX as the return value, as stated earlier
After execution, the main function of the var1=7;ret=0;
Next, we're going to call __stdcall's function, which is the old Pascal that uses this convention, but the point is that all Windows APIs also use this Convention
So let's just find out!
124: ret = Fnstandardcall (8, 9, ten, &var1); 00401380 Lea ecx,[ebp-14h]00401383 Push ecx00401384 push 0ah00401386 push 900401388 push 80040138A call @ILT +20 ( Fnstandardcall) (00401019) 0040138F mov dword ptr [ebp-18h],eax125:
From the command of the call to see, careful you will immediately find that the little girl's body seems to be missing something pendant, Amitabha, sin!
Yes, the previous function call after the end of the add esp,xxx the previous push parameters are ejected, here is not, really strange!
Then we'll track into the dark alley and see what he's done!
37:int __stdcall fnstandardcall (int arg1, short arg2, char arg3, void *arg4): {00401200 push ebp00401201 MOV ebp,esp00401203 sub esp,50h00401206 push ebx00401207 push esi00401208 push edi00401209 Lea edi,[ebp-50h]0040120c mov ecx,14h00401211 mov eax,0cccccccch00401216 re P STOs DWORD ptr [Edi]39:int var1;40:short var2;41:char Var3;42:int *p;43:44:var1 = arg1;00401218 mov eax,dword ptr [ebp+8]0040121b mov dword ptr [EBP-4],EAX45:VAR2 = arg2;0040121 E mov cx,word ptr [ebp+0ch]00401222 mov word ptr [ebp-8],cx46:var3 = arg3;00401226 mov Dl,byte ptr [ebp+10h]00401229 mov byte ptr [ebp-0ch],dl47:p = (int *) ARG4;0040122C mov eax,dw Ord ptr [ebp+14h]0040122f mov dword ptr [ebp-10h],eax48: *p = 11;00401232 mov ecx,dword ptr [EBP] -10H]00401235 mov DWORD ptr [Ecx],0bh49:50:return 0;0040123b xor eax,eax51:}0040123d pop edi0040123e Pop esi0040123f pop ebx00401240 mov esp,ebp00401242 pop ebp00401243 ret 10h
The above things and the default __cdecl convention a touch, once Thai said: "mentor says, Tittle!"
Finally is the key, the former RET, turned to RET 10h, ran to this, or said merge here, Yuan Fang said: "The truth of the matter is actually so!"
This so-called maintenance stack, is just finished, who will clean the scene!
This is not entirely superficial, such as the API just pass in the parameters, get the return value, so this is a lazy to the caller of the Convention.
Then the next is Fastcall, as the name suggests should be a quick call, how a quick Method? See call
125:126: ret = Fnfastcall (one, one, and &var1); 00401392 Lea edx,[ebp-14h]00401395 Push edx00401396 push 0dh00401398 mov edx,0ch0040139d mov ecx,0bh004013a2 call @ Ilt+25 (Fnfastcall) (0040101e) 004013a7 mov dword ptr [ebp-18h],eax127:
obediently, there are only two push, the first second parameter is directly transmitted ECX and edx, the other with the __stdcall a touch!
Is it okay to push or not? This question should be asked, why must push to be able to do it! Let's follow it up in detail:
: int __fastcall fnfastcall (int arg1, short arg2, char arg3, void *arg4): {00401260 push ebp00401261 mov ebp,esp00401263 Sub esp,58h00401266 push ebx00401267 push esi00401268 push edi00401269 push ecx0040126a Lea edi,[ebp-58h]0040126d mov ecx,16h00401272 mov eax,0cccccccch00401277 rep stos dword ptr [edi]00401279 pop ecx0040127a mov word ptr [ebp-8],dx0040127e mov dword ptr [EBP-4],ECX
The key is in the preceding instructions, when creating the function temporary stack, the compiler protects the two registers and then automatically creates two local variables to save them.
So, the compiler is not a human being, it doesn't matter! Thus, the efficiency of C + + is high, and normal programmers write programs that are much worse than assembly language, unless inline assembly or optimized
In the future when we talk about naked functions, this is the point where the code behind the function is understandable, almost identical to the previous one.
65:66: return 0;004012a4 xor eax,eax67: }004012a6 pop edi004012a7 pop Esi004012a8 pop ebx004012a9 mov esp,ebp004012ab pop ebp004012ac ret 8
Pay attention to the back of RET 8, because after the direct recovery of ESP, so the process of push are quietly pop
Then we say thiscall, when a member variable of a class is called, the this pointer is passed automatically, so thiscall is an implicit declaration
Let's take a look at the assembly instructions for the new object:
£ º Pcall = new Ccall (), 004013AA push 4004013AC call operator new (004015b0) 004013b1 add esp,4004013b4 mov dword ptr [EBP-20H],EAX004013B7 mov dword ptr [EBP-4],0004013BE CMP DWORD ptr [ebp-20h],0004013c2 je main+0a1h (004013d1) 004013c4 mov ecx,dword ptr [ebp-20h] 004013c7 Call @ILT +35 (ccall::ccall) (00401028) 004013CC mov dword ptr [EBP-2CH],EAX004013CF jmp main+0a8h (004013d8) 004013d1 mov dword ptr [Ebp-2ch],0004013d8 mov eax,dword ptr [ebp-2ch]004013db mov dword ptr [ebp-1ch],eax004013de mov dword ptr [Ebp-4], 0ffffffffh004013e5 mov ecx,dword ptr [ebp-1ch]004013e8 mov dword ptr [EBP-10H],ECX
At this level, new is actually a function. And as you can see, the memory size of Ccall is four bytes.
Returned after saving to Pcall that is [ebp-20], here suddenly a mov [ebp-4], 0, after we say
Then determine whether the returned pointer is a NULL,CMP instruction, if NULL jumps to 0X004013D1, that is, MOV dword ptr [ebp-2ch],0 this
If you do not continue execution for zero
mov Ecx,dword ptr [ebp-20h]
Call @ILT +35 (Ccall::ccall) (00401028)
[ebp-20] is Pcall,call is the class of the constructor, coax, the original transferred this to the ecx inside, and then follow the look at the constructor
00401079 push ecx0040107a Lea edi,[ebp-44h]0040107d mov ecx,11h00401082 mov eax,0cccccccch00401087 Rep STOs dword ptr [edi]00401089 pop ecx0040108a mov dword ptr [ ebp-4],ecx6: m_var1 = 18;0040108d mov eax,dword ptr [ebp-4]00401090 mov dword ptr [EAX], 12h7: }00401096 mov eax,dword ptr [ebp-4]
Save the ECX (that is, the thsi pointer), create a temporary stack, create a temporary variable instead of ECX, [ebp-4], because M_VAR1 is the first member, the class occupies only 4 bytes
So the direct transfer to EAX that [ebp-4], and then the value of ebp-4 to EAX, you can see the compiler around a large section of bend, which is why the previous talk about the game view of the time
I use C as much as possible, instead of C + +, as you can see, the constructor has a return value, and the return value is this!
Go back to the calling code, jump straight after normal initialization, skip the new failed
004013D1 mov dword ptr [ebp-2ch],0
Then a large pile of MOV transmission, EAX is the return value of this, passed to [ebp-2c], and then if new failure [EBP-2C] and passed in 0, and then passed to eax, and then passed to [EBP-1C]!!!
As a pursuit of the perfect technical staff, would be anxious to put Microsoft hacked!
See the new return value before the evaluation of a [ebp-4] assignment is 0, at this time to assign a value of 1, and then the [ebp-1c] transmitted to the 0 passed to ECX, and then ecx to [ebp-10], no words!
Don't look so much flying, if the normal initialization execution succeeds, [ebp-10] is a pointer to the class, if new fails the 0 is the null!
Here is the call to the member function:
129: ret = Pcall->call (&var1), 004013EB Lea edx,[ebp-14h]004013ee Push Edx004013ef push 11h004013f1 push 10h004013f3 push 0fh004013f5 mov ecx, DWORD ptr [Ebp-10h]004013f8 call @ILT +30 (ccall::call) (00401023) 004013FD mov dword ptr [ebp-18h ],eax
The same this pointer is passed to the ECX, and the return value is saved in the EAX register. The parameters are entered in the stack from right to left. Stack member function Auto cleanup
004010E9 push ecx004010ea Lea edi,[ebp-54h]004010ed mov ecx,15h004010f2 mov eax,0cc Cccccch004010f7 Rep stos dword ptr [edi]004010f9 pop ECX004010FA mov dword ptr [ebp-4],ecx15: int Var1;16:short Var2;17:char Var3;18:int *p;19:var1 = ARG1;004010FD mov Eax,dwo RD PTR [ebp+8]00401100 mov dword ptr [EBP-8],EAX20:VAR2 = arg2;00401103 mov cx,word ptr [ebp+0c H]00401107 mov word ptr [ebp-0ch],cx21:var3 = arg3;0040110b mov dl,byte ptr [ebp+10h]0040110e mov byte ptr [ebp-10h],dl22:p = (int *) arg4;00401111 mov eax,dword ptr [ebp+14h]00401114 mov DWORD ptr [ebp-14h],eax23: *p = m_var1;00401117 mov ecx,dword ptr [ebp-14h]0040111a mov E Dx,dword ptr [ebp-4]0040111d mov eax,dword ptr [edx]0040111f mov dword ptr [Ecx],eax24:return 0 ; 00401121 XOREAX,EAX25:}
As you can see, you still create a temporary variable to hold ECX (that is, [ebp-4]), and then use this to refer to the member variable, thiscall is more verbose than the various calling conventions above
are slow, but this is the cost of object-oriented object, development and maintenance is simpler, the sacrifice is the execution efficiency, this can only rely on hardware performance to compensate;
Similarly. NET development and maintenance debugging super easy, fault-tolerant ability is extremely powerful, also sacrificed security, in front of dis#, the source code completely exposed ...
Then again Int3 time, the following we say the last function of the knowledge, bare function!
About the invocation of a compiled language function (ii)