<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>代码分析</title><link>http://blog.vckbase.com/jozu/category/196.html</link><description>代码分析</description><managingEditor>Coder Jozu</managingEditor><dc:language>af</dc:language><generator>.Text Version 0.958.2004.214</generator><item><dc:creator>Coder Jozu</dc:creator><title>Run before CRT</title><link>http://blog.vckbase.com/jozu/articles/1035.html</link><pubDate>Mon, 25 Oct 2004 19:32:00 GMT</pubDate><guid>http://blog.vckbase.com/jozu/articles/1035.html</guid><wfw:comment>http://blog.vckbase.com/jozu/comments/1035.html</wfw:comment><comments>http://blog.vckbase.com/jozu/articles/1035.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://blog.vckbase.com/jozu/comments/commentRss/1035.html</wfw:commentRss><trackback:ping>http://blog.vckbase.com/jozu/services/trackbacks/1035.html</trackback:ping><description>&lt;P&gt;// &lt;BR&gt;// Run before main &lt;BR&gt;// &lt;BR&gt;// Coder: Jozu &lt;BR&gt;#include &lt;STDLIB.H&gt;&lt;BR&gt;#include &lt;STDIO.H&gt;&lt;BR&gt;&lt;BR&gt;int main(int argc, char** argv) &lt;BR&gt;{ &lt;BR&gt;printf("This is from main.\n"); &lt;BR&gt;return 0; &lt;BR&gt;} &lt;BR&gt;&lt;BR&gt;int beforemain(void) &lt;BR&gt;{ &lt;BR&gt;printf("This is before main.\n"); &lt;BR&gt;return 0; &lt;BR&gt;} &lt;BR&gt;&lt;BR&gt;int aftermain(void) &lt;BR&gt;{ &lt;BR&gt;printf("This is after amin.\n"); &lt;BR&gt;return 0; &lt;BR&gt;} &lt;BR&gt;&lt;BR&gt;typedef int cb(void); &lt;BR&gt;&lt;BR&gt;#pragma data_seg(".CRT$XID") &lt;BR&gt;static cb *startfuncs[] = { beforemain }; &lt;BR&gt;&lt;BR&gt;#pragma data_seg(".CRT$XTD") &lt;BR&gt;static cb *exitfuncs[] = { aftermain }; &lt;BR&gt;&lt;BR&gt;#pragma data_seg() ???/* reset data-segment */&lt;/P&gt;
&lt;P&gt;说明：&lt;/P&gt;
&lt;P&gt;?参考VC自带的CRT源代码，我们可以看到一个程序的最初是从&lt;/P&gt;
&lt;P&gt;mainCRTStartup (console) 或者 WinMainCRTStartup开始的，仔细分析代码（crtexec.c），可以看到下面的一段：&lt;/P&gt;
&lt;P&gt;/*&lt;BR&gt;?* Do runtime startup initializers.&lt;BR&gt;*/&lt;BR&gt;_initterm( __xi_a, __xi_z );&lt;/P&gt;
&lt;P&gt;和接着下面的&lt;/P&gt;
&lt;P&gt;?/*&lt;BR&gt;? * do C++ constructors (initializers) specific to this EXE&lt;BR&gt;*/&lt;BR&gt;_initterm( __xc_a, __xc_z );&lt;/P&gt;
&lt;P&gt;这两句话什么意思呢，看看代码(crt0dat.c)：&lt;/P&gt;
&lt;P&gt;#ifdef CRTDLL&lt;BR&gt;void __cdecl _initterm (&lt;BR&gt;#else? /* CRTDLL */&lt;BR&gt;static void __cdecl _initterm (&lt;BR&gt;#endif? /* CRTDLL */&lt;BR&gt;??????? _PVFV * pfbegin,&lt;BR&gt;??????? _PVFV * pfend&lt;BR&gt;??????? )&lt;BR&gt;{&lt;BR&gt;??????? /*&lt;BR&gt;???????? * walk the table of function pointers from the bottom up, until&lt;BR&gt;???????? * the end is encountered.? Do not skip the first entry.? The initial&lt;BR&gt;???????? * value of pfbegin points to the first valid entry.? Do not try to&lt;BR&gt;???????? * execute what pfend points to.? Only entries before pfend are valid.&lt;BR&gt;???????? */&lt;BR&gt;??????? while ( pfbegin &lt; pfend )&lt;BR&gt;??????? {&lt;BR&gt;??????????? /*&lt;BR&gt;???????????? * if current table entry is non-NULL, call thru it.&lt;BR&gt;???????????? */&lt;BR&gt;??????????? if ( *pfbegin != NULL )&lt;BR&gt;??????????????? (**pfbegin)();&lt;BR&gt;??????????? ++pfbegin;&lt;BR&gt;??????? }&lt;BR&gt;}&lt;/P&gt;
&lt;P&gt;函数本身很简单，就是依次调用一个串连起来的函数表，那么pfbegin和pfend又是怎么来的呢，继续挖掘（cinitexe.c）：&lt;/P&gt;
&lt;P&gt;#pragma data_seg(".CRT$XIA")&lt;BR&gt;PFV __xi_a = 0;? /* C initializers */&lt;/P&gt;
&lt;P&gt;#pragma data_seg(".CRT$XIZ")&lt;BR&gt;PFV __xi_z????? = 0;&lt;/P&gt;
&lt;P&gt;#pragma data_seg(".CRT$XCA")&lt;BR&gt;PFV __xc_a = 0;? /* C++ initializers */&lt;/P&gt;
&lt;P&gt;#pragma data_seg(".CRT$XCZ")&lt;BR&gt;PFV __xc_z = 0;&lt;/P&gt;
&lt;P&gt;#pragma data_seg(".CRT$XPA")&lt;BR&gt;PFV __xp_a = 0;? /* C pre-terminators */&lt;/P&gt;
&lt;P&gt;#pragma data_seg(".CRT$XPZ")&lt;BR&gt;PFV __xp_z = 0;&lt;/P&gt;
&lt;P&gt;#pragma data_seg(".CRT$XTA")&lt;BR&gt;PFV __xt_a = 0;?? /* C terminators */&lt;/P&gt;
&lt;P&gt;#pragma data_seg(".CRT$XTZ")&lt;BR&gt;PFV __xt_z = 0;&lt;/P&gt;
&lt;P&gt;#pragma data_seg()? /* reset */&lt;BR&gt;&lt;/P&gt;
&lt;P&gt;看来这个是关键，就是说在编译期间，编译器把每一个obj中要初始化调用的函数表编译形成一个段，连接的时候，把这些段合并存储在一个数据段上，这样一个初始化表就形成了，程序启动的时候，这些函数就会被依次调用。&lt;/P&gt;
&lt;P&gt;ok。总结一下：&lt;/P&gt;
&lt;P&gt;程序真正的起始点是CRT的函数，这个函数负责初始化必要的数据结构，产生命令行（就是main要用到的argc，argv），初始化变量，调用全局对象的构造函数，等等，然后把控制权交给main。&lt;/P&gt;
&lt;P&gt;知道了整个过程，想来理解上面的代码应该没有问题了。&lt;/P&gt;
&lt;P&gt;Have a good day!&lt;/P&gt;&lt;img src ="http://blog.vckbase.com/jozu/aggbug/1035.html" width = "1" height = "1" /&gt;</description></item></channel></rss>