c 语言的构成就是函数 现在写一写心得和体会
在函数中毫无疑问 第一个函数无疑是创世之作 一般来说刚刚学习c语言的适合main 函数无疑是遇见的第一个函数那么就结合main 函数的初始化 以及如何用汇编调用main 函数写一篇心得
#include <stdio.h>
int main()
{
010E1810 push ebp
010E1811 mov ebp,esp
010E1813 sub esp,0C0h
010E1819 push ebx
010E181A push esi
010E181B push edi
010E181C lea edi,[ebp-0C0h]
010E1822 mov ecx,30h
010E1827 mov eax,0CCCCCCCCh
010E182C rep stos dword ptr es:[edi]
printf("hello\n");
010E182E push offset string "hello\n" (010E6B30h)
010E1833 call _printf (010E1320h)
010E1838 add esp,4
return 0;
010E183B xor eax,eax
}
010E183D pop edi
010E183E pop esi
010E183F pop ebx
010E1840 add esp,0C0h
010E1846 cmp ebp,esp
010E1848 call __RTC_CheckEsp (010E1113h)
010E184D mov esp,ebp
010E184F pop ebp
010E1850 ret
这是一段汇编代码 先解释如何使用栈
首先先要清楚 每次push esp 都会增加
也就是这个
这个是main 函数刚刚进的时候的图
接下来分析 另外一个代码
int main()
{
00EF1740 push ebp
00EF1741 mov ebp,esp
00EF1743 sub esp,0E4h
00EF1749 push ebx
00EF174A push esi
00EF174B push edi
00EF174C lea edi,[ebp-0E4h]
00EF1752 mov ecx,39h
00EF1757 mov eax,0CCCCCCCCh
00EF175C rep stos dword ptr es:[edi]
int a =20;
00EF175E mov dword ptr [a],14h
int b = a;
00EF1765 mov eax,dword ptr [a]
00EF1768 mov dword ptr [b],eax
int c=add(10, 10);
00EF176B push 0Ah
00EF176D push 0Ah
00EF176F call add (0EF126Ch)
00EF1774 add esp,8
00EF1777 mov dword ptr [c],eax
return 0;
00EF177A xor eax,eax
}
00EF177C pop edi
00EF177D pop esi
00EF177E pop ebx
00EF177F add esp,0E4h
00EF1785 cmp ebp,esp
00EF1787 call __RTC_CheckEsp (0EF110Eh)
00EF178C mov esp,ebp
00EF178E pop ebp
00EF178F ret
前面就不说了 就看函数调用add(10,10)
同时我们为了通俗易懂 我们把ebp寄存器里现有的值就叫 手上edp 把之前的值叫做 老edp
如何执行 先看内存
接下来验证是否一致 进入函数后
入口地址刚好是由于是小端 低地址放低位 即
00ef1774 即
00EF1700 push ebp
00EF1701 mov ebp,esp
00EF1703 sub esp,0C0h
00EF1709 push ebx
00EF170A push esi
00EF170B push edi
00EF170C lea edi,[ebp-0C0h]
00EF1712 mov ecx,30h
00EF1717 mov eax,0CCCCCCCCh
00EF171C rep stos dword ptr es:[edi]
return a + b;
00EF171E mov eax,dword ptr [a]
00EF1721 add eax,dword ptr [b]
}
00EF1724 pop edi
00EF1725 pop esi
00EF1726 pop ebx
00EF1727 mov esp,ebp
00EF1729 pop ebp
00EF172A ret
执行完之后
push ebp
即
20 f9 93 00
0x0093F824 74 17 ef 00
将手中的edp=93f920和图中测试一样 压入栈得出
同时接下来使得edp=esp 这样手上又有了edp得副本 很容易还原函数
这样下来规律自然体现
因此这个图可以完善了
程序员自我修养上
图是这样得
我认为确切得从内存上来看是这样得
这个图是有一点点和常规不一样 这样是从后面地址得出前面的值
也就是 *手上的edp 可以得出的是老edp
总而言之 栈的进和出也已经差不多了 我没有写返回值 因为有的函数没有返回地址 其实返回int类型什么的都是通过eax寄存器带出来的 所以也就没有写明
接下来就是程序的入口地址
其实也有说明 我们不断执行下一步
static void __cdecl pre_cpp_initialization() throw()
{
// Before we begin C++ initialization, set the unhandled exception
// filter so that unhandled C++ exceptions result in std::terminate
// being called:
__scrt_set_unhandled_exception_filter();
_set_new_mode(_get_startup_new_mode());
}
// When both the PGO instrumentation library and the CRT are statically linked,
// PGO will initialize itself in XIAB. We do most pre-C initialization before
// PGO is initialized, but defer some initialization steps to after. See the
// commentary in post_pgo_initialization for details.
_CRTALLOC(".CRT$XIAA") static _PIFV pre_c_initializer = pre_c_initialization;
_CRTALLOC(".CRT$XIAC") static _PIFV post_pgo_initializer = post_pgo_initialization;
_CRTALLOC(".CRT$XCAA") static _PVFV pre_cpp_initializer = pre_cpp_initialization;
static __declspec(noinline) int __cdecl __scrt_common_main_seh() throw()
{
if (!__scrt_initialize_crt(__scrt_module_type::exe))
__scrt_fastfail(FAST_FAIL_FATAL_APP_EXIT);
bool has_cctor = false;
__try
{
bool const is_nested = __scrt_acquire_startup_lock();
if (__scrt_current_native_startup_state == __scrt_native_startup_state::initializing)
{
__scrt_fastfail(FAST_FAIL_FATAL_APP_EXIT);
}
else if (__scrt_current_native_startup_state == __scrt_native_startup_state::uninitialized)
{
__scrt_current_native_startup_state = __scrt_native_startup_state::initializing;
if (_initterm_e(__xi_a, __xi_z) != 0)
return 255;
_initterm(__xc_a, __xc_z);
__scrt_current_native_startup_state = __scrt_native_startup_state::initialized;
}
else
{
has_cctor = true;
}
__scrt_release_startup_lock(is_nested);
// If this module has any dynamically initialized __declspec(thread)
// variables, then we invoke their initialization for the primary thread
// used to start the process:
_tls_callback_type const* const tls_init_callback = __scrt_get_dyn_tls_init_callback();
if (*tls_init_callback != nullptr && __scrt_is_nonwritable_in_current_image(tls_init_callback))
{
(*tls_init_callback)(nullptr, DLL_THREAD_ATTACH, nullptr);
}
// If this module has any thread-local destructors, register the
// callback function with the Unified CRT to run on exit.
_tls_callback_type const * const tls_dtor_callback = __scrt_get_dyn_tls_dtor_callback();
if (*tls_dtor_callback != nullptr && __scrt_is_nonwritable_in_current_image(tls_dtor_callback))
{
_register_thread_local_exe_atexit_callback(*tls_dtor_callback);
}
//
// Initialization is complete; invoke main...
//
int const main_result = invoke_main();
//
// main has returned; exit somehow...
//
if (!__scrt_is_managed_app())
exit(main_result);
if (!has_cctor)
_cexit();
// Finally, we terminate the CRT:
__scrt_uninitialize_crt(true, false);
return main_result;
}
如果追寻到底就是
extern "C" int mainCRTStartup()
{
return __scrt_common_main();
}
在exe.cpp里面