VS2013+WIN7+Debug
--- g:codingpoet estctest.cpp ---------------------------------------------- #include <iostream> using namespace std; int main() { ;将ebp入栈,保存ebp,保护原现场 00D252A0 push ebp ;将esp传送给ebp 00D252A1 mov ebp,esp ;esp减去0C0h,开辟栈空间存放局部变量 ;注意汇编语言中数字常量如果是字母开头必须加上0 00D252A3 sub esp,0C0h ;保存常用的寄存器ebx,esi,edi,保护原现场 00D252A9 push ebx 00D252AA push esi 00D252AB push edi ;将edi赋值为ebp-0C0h(lea取得偏移地址) 00D252AC lea edi,[ebp-0C0h] ;30h(临时栈区大小,4字节为单位)放入ecx,为rep执行次数 ;注意到30h * 4字节 = 0C0h 00D252B2 mov ecx,30h ;0CCCCCCCCh为系统中断int 3h,也是临时栈区初始值 00D252B7 mov eax,0CCCCCCCCh ;用int 3h循环填充临时栈区 00D252BC rep stos dword ptr es:[edi] return 0; ;等价于mov eax, 0但是xor更高效 00D252BE xor eax,eax } ;恢复寄存器ebx,esi,edi 00D252C0 pop edi 00D252C1 pop esi 00D252C2 pop ebx ;用ebp恢复函数调用前的栈指针esp 00D252C3 mov esp,ebp ;恢复ebp 00D252C5 pop ebp ;返回 00D252C6 ret
栈区开辟的存储空间都是使用0CCCCCCCCh来填充4字节单位的,也就是说,栈区开辟的存取局部变量的空间的每一个字节都被0xCC填充了。(为什么用0xCC,这个是int 3h的机器码,下断点用的)
未初始化的变量会被系统赋初值为0xCC,超过了ASCII码0-127这个范围,因此这个“字符串”被系统当成了宽字符组成的字符串,即两个字节数据组成一个字符,而0xCCCC表示的宽字符正好是乱码中的那个“烫”字。
#include <stdio.h> #include <string.h> int main() { char s[100]; memset(s, 0xcc, sizeof(s)); printf("%s ", s); return 0; }
动态分配的空间开辟与堆,VC的Debug用0xCD填充堆的空间,两个0xCD和在一起就是屯了。
; The ebp register is used to access local variables that are stored on the stack,
; this is known as a stack frame. Before we start doing anything, we need to save
; the stack frame of the calling function so it can be restored when we finish.
push ebp
; These two instructions create our stack frame, in this case, 192 bytes
; This space, although not used in this case, is useful for edit-and-continue. If you
; break the program and add code which requires a local variable, the space is
; available for it. This is much simpler than trying to relocate stack variables,
; especially if you have pointers to stack variables.
mov ebp,esp
d sub esp,0C0h
; C/C++ functions shouldn't alter these three registers in this build configuration,
; so save them. These are stored below our stack frame (the stack moves down in memory)
r push ebx
r push esi
r push edi
; This puts the address of the stack frame bottom (lowest address) into edi...
d lea edi,[ebp-0C0h]
; ...and then fill the stack frame with the uninitialised data value (ecx = number of
; dwords, eax = value to store)
d mov ecx,30h
d mov eax,0CCCCCCCCh
d rep stos dword ptr es:[edi]
; Stack checking code: the stack pointer is stored in esi
r mov esi,esp
; This is the first parameter to printf. Parameters are pushed onto the stack
; in reverse order (i.e. last parameter pushed first) before calling the function.
push offset SimpleDemo!`string'
; This is the call to printf. Note the call is indirect, the target address is
; specified in the memory address SimpleDemo!_imp__printf, which is filled in when
; the executable is loaded into RAM.
call dword ptr [SimpleDemo!_imp__printf]
; In C/C++, the caller is responsible for removing the parameters. This is because
; the caller is the only code that knows how many parameters were put on the stack
; (thanks to the '...' parameter type)
add esp,4
; More stack checking code - this sets the zero flag if the stack pointer is pointing
; where we expect it to be pointing.
r cmp esi,esp
; ILT - Import Lookup Table? This is a statically linked function which throws an
; exception/error if the zero flag is cleared (i.e. the stack pointer is pointing
; somewhere unexpected)
r call SimpleDemo!ILT+295(__RTC_CheckEsp))
; The return value is stored in eax by convention
xor eax,eax
; Restore the values we shouldn't have altered
r pop edi
r pop esi
r pop ebx
; Destroy the stack frame
r add esp,0C0h
; More stack checking code - this sets the zero flag if the stack pointer is pointing
; where we expect it to be pointing.
r cmp ebp,esp
; see above
r call SimpleDemo!ILT+295(__RTC_CheckEsp)
; This is the usual way to destroy the stack frame, but here it's not really necessary
; since ebp==esp
mov esp,ebp
; Restore the caller's stack frame
pop ebp
; And exit
ret
; Debug only, no runtime checks
push ebp
mov ebp,esp
d sub esp,0C0h
d lea edi,[ebp-0C0h]
d mov ecx,30h
d mov eax,0CCCCCCCCh
d rep stos dword ptr es:[edi]
push offset SimpleDemo!`string'
call dword ptr [SimpleDemo!_imp__printf]
add esp,4
xor eax,eax
mov esp,ebp
pop ebp
ret
; Release mode (I'm assuming the optimiser is clever enough to drop the stack frame when there's no local variables)
push offset SimpleDemo!`string'
call dword ptr [SimpleDemo!_imp__printf]
add esp,4
xor eax,eax
ret
http://stackoverflow.com/questions/4024492/can-anyone-help-me-interpret-this-simple-disassembly-from-windbg