From 7001e9c49a48df256fd9ec6ed29ed0e81f4d2128 Mon Sep 17 00:00:00 2001 From: DapperZhengLong <142093590+DapperZhengLong@users.noreply.github.com> Date: Sat, 21 Sep 2024 19:26:25 +0800 Subject: [PATCH] =?UTF-8?q?Delete=20content=20src/site/notes/=E7=BC=96?= =?UTF-8?q?=E7=A8=8B=E8=AF=AD=E8=A8=80/c++/=E8=AE=A4=E8=AF=86=E5=90=AF?= =?UTF-8?q?=E5=8A=A8=E5=87=BD=E6=95=B0.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...57\345\212\250\345\207\275\346\225\260.md" | 47 ------------------- 1 file changed, 47 deletions(-) delete mode 100644 "src/site/notes/\347\274\226\347\250\213\350\257\255\350\250\200/c++/\350\256\244\350\257\206\345\220\257\345\212\250\345\207\275\346\225\260.md" diff --git "a/src/site/notes/\347\274\226\347\250\213\350\257\255\350\250\200/c++/\350\256\244\350\257\206\345\220\257\345\212\250\345\207\275\346\225\260.md" "b/src/site/notes/\347\274\226\347\250\213\350\257\255\350\250\200/c++/\350\256\244\350\257\206\345\220\257\345\212\250\345\207\275\346\225\260.md" deleted file mode 100644 index 63429b6..0000000 --- "a/src/site/notes/\347\274\226\347\250\213\350\257\255\350\250\200/c++/\350\256\244\350\257\206\345\220\257\345\212\250\345\207\275\346\225\260.md" +++ /dev/null @@ -1,47 +0,0 @@ ---- -{"dg-publish":true,"permalink":"/编程语言/c++/认识启动函数/","dgPassFrontmatter":true} ---- - -```c -#include - -int main(int argc, char* argv[]) { - int arr[] = { 1, 2, 3, 4 }; - int *p = arr; // p 指向 arr 的首元素,即 arr[0] - p = p + 2; // p 向后移动 2 个 int 类型的位置(如果在32位系统中,将移动 2 * 4 = 8 字节),现在 p 指向 arr[2] - - return 0; -} -``` -在执行 C 或 C++ 程序时,尽管 `main()`、`WinMain()` 函数等看似程序入口,但在实际过程中,还有一些底层的设置和初始化工作需要在主函数之前完成。这些初始化工作由编译器自动生成的代码和操作系统来完成。 - -在Windows环境下,程序的真正入口点是操作系统识别可执行文件的一个特定区域,通常是 `mainCRTStartup`、`wmainCRTStartup`、`WinMainCRTStartup` 或 `wWinMainCRTStartup` 函数,具体取决于编译选项和环境。这些运行时环境启动函数在 `main()` 或 `WinMain()` 函数之前执行,以完成必要的初始化工作,如堆设置、全局变量初始化和其他工作。 - -执行了启动函数后,程序会调用主函数 `main()` 或 `WinMain()`,在这里,开发者编写的代码才会开始执行。 -# main函数之前的函数 -mainCRTStartup中调用main函数。我们无法查看mainCRTStartup函数之前的高级源码。 -## mainCRTStartup函数的工作流程 -1. `__security_init_cookie` 函数:用于初始化一个全局变量,这个变量在之后将用于检测缓冲区溢出。缓冲区溢出是一种常见的安全漏洞,可能导致程序崩溃,甚至允许恶意攻击者执行任意代码。这个函数的主要目的是在运行时提供一种额外的安全保护,以确保缓冲区不会溢出。无参数 -2. `_initterm_e` 函数:用于在程序启动期间初始化全局数据和浮点寄存器。这个函数接收两个参数(类型为 `_PIFV *`) -3. `_initterm` 函数是在 C++ 程序启动时执行的一个特殊函数,用于完成如全局对象、I/O 流等的初始化。`_initterm` 函数接受两个参数,它们的类型为 `_PVFV *` -4. `__scrt_get_dyn_tls_init_callback` 函数:获取线程局部存储(TLS)变量的回调函数,用于初始化使用 `__declspec(thread)` 定义的变量。无参数 -5. `__scrt_get_dyn_tls_dtor_callback` 函数:获取线程局部存储变量的析构回调函数,用于注册析构回调函数。无参数 -6. `invoke_main` 函数:该函数获取 `main` 函数所需的3个参数信息之后,当调用 `main` 函数时,便可以将 `_argc`、`_argv`、`env` 这3个全局变量作为参数,传递到 `main` 函数中。三个参数。他调用main函数 -7. `exit` 函数:执行析构函数或 `atexit` 注册的函数指针,并结束程序。无参数 -## main函数的识别 -虽然`int main(int argc, char *argv[]);int main(void)`都是可以被接受的,但是不管我们代码中实际使用了几个参数,在程序被编译时其main函数肯定是三个参数的,且有两个参数为地址,因为这取决于Windows系统的机制。且应用程序会随着main函数结束而退出,这又给了我们第二个有力的特征,既main函数肯定是在程序退出代码附近的 -``` -.text:00411E8A add esp, 4 -.text:00411E8D movzx ecx, al -.text:00411E90 test ecx, ecx -.text:00411E92 jz short loc_411EA2 -.text:00411E94 mov edx, [ebp+var_24] -.text:00411E97 mov eax, [edx] -.text:00411E99 push eax ; Callback -.text:00411E9A call j___register_thread_local_exe_atexit_callback -.text:00411E9F add esp, 4 -.text:00411EA2 -.text:00411EA2 loc_411EA2: ; CODE XREF: __scrt_common_main_seh(void)+12F↑j -.text:00411EA2 ; __scrt_common_main_seh(void)+142↑j -.text:00411EA2 call ?invoke_main@@YAHXZ ; invoke_main(void) -``` \ No newline at end of file