Coder Jozu

I believe --- 这里坚持原创,拒绝转贴

  VC知识库BLOG :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 登录 ::
  13 随笔 :: 4 文章 :: 87 评论 :: 1 Trackbacks
<2006年11月>
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789

留言簿(4)

随笔分类

随笔档案

文章分类

文章档案

东接西链

搜索

最新评论

阅读排行榜

评论排行榜

//
// Run before main
//
// Coder: Jozu
#include
#include

int main(int argc, char** argv)
{
printf("This is from main.\n");
return 0;
}

int beforemain(void)
{
printf("This is before main.\n");
return 0;
}

int aftermain(void)
{
printf("This is after amin.\n");
return 0;
}

typedef int cb(void);

#pragma data_seg(".CRT$XID")
static cb *startfuncs[] = { beforemain };

#pragma data_seg(".CRT$XTD")
static cb *exitfuncs[] = { aftermain };

#pragma data_seg() ???/* reset data-segment */

说明:

?参考VC自带的CRT源代码,我们可以看到一个程序的最初是从

mainCRTStartup (console) 或者 WinMainCRTStartup开始的,仔细分析代码(crtexec.c),可以看到下面的一段:

/*
?* Do runtime startup initializers.
*/
_initterm( __xi_a, __xi_z );

和接着下面的

?/*
? * do C++ constructors (initializers) specific to this EXE
*/
_initterm( __xc_a, __xc_z );

这两句话什么意思呢,看看代码(crt0dat.c):

#ifdef CRTDLL
void __cdecl _initterm (
#else? /* CRTDLL */
static void __cdecl _initterm (
#endif? /* CRTDLL */
??????? _PVFV * pfbegin,
??????? _PVFV * pfend
??????? )
{
??????? /*
???????? * walk the table of function pointers from the bottom up, until
???????? * the end is encountered.? Do not skip the first entry.? The initial
???????? * value of pfbegin points to the first valid entry.? Do not try to
???????? * execute what pfend points to.? Only entries before pfend are valid.
???????? */
??????? while ( pfbegin < pfend )
??????? {
??????????? /*
???????????? * if current table entry is non-NULL, call thru it.
???????????? */
??????????? if ( *pfbegin != NULL )
??????????????? (**pfbegin)();
??????????? ++pfbegin;
??????? }
}

函数本身很简单,就是依次调用一个串连起来的函数表,那么pfbegin和pfend又是怎么来的呢,继续挖掘(cinitexe.c):

#pragma data_seg(".CRT$XIA")
PFV __xi_a = 0;? /* C initializers */

#pragma data_seg(".CRT$XIZ")
PFV __xi_z????? = 0;

#pragma data_seg(".CRT$XCA")
PFV __xc_a = 0;? /* C++ initializers */

#pragma data_seg(".CRT$XCZ")
PFV __xc_z = 0;

#pragma data_seg(".CRT$XPA")
PFV __xp_a = 0;? /* C pre-terminators */

#pragma data_seg(".CRT$XPZ")
PFV __xp_z = 0;

#pragma data_seg(".CRT$XTA")
PFV __xt_a = 0;?? /* C terminators */

#pragma data_seg(".CRT$XTZ")
PFV __xt_z = 0;

#pragma data_seg()? /* reset */

看来这个是关键,就是说在编译期间,编译器把每一个obj中要初始化调用的函数表编译形成一个段,连接的时候,把这些段合并存储在一个数据段上,这样一个初始化表就形成了,程序启动的时候,这些函数就会被依次调用。

ok。总结一下:

程序真正的起始点是CRT的函数,这个函数负责初始化必要的数据结构,产生命令行(就是main要用到的argc,argv),初始化变量,调用全局对象的构造函数,等等,然后把控制权交给main。

知道了整个过程,想来理解上面的代码应该没有问题了。

Have a good day!

posted on 2004-10-26 03:32 Coder Jozu 阅读(3261) 评论(5)  编辑 收藏

评论

# re: Run before CRT 2004-10-26 03:41 兔狸熊
好文章啊,


# 没说的,顶一下吧!:) 2004-10-26 04:15 一笑
rt

# re: Run before CRT 2006-11-11 17:10 dabang
绝对的强人!
向你学习ing

# re: Run before CRT 2008-10-15 10:59 kemin
这也叫好文章?有尾没头,不知道在干啥,或许有点用,可惜我不想看,

# re: Run before CRT 2008-10-15 12:14 布伦特原油
Nice Job!

标题  
姓名  
主页
验证码 *
内容   
  登录  使用高级评论  Top
[使用Ctrl+Enter键可以直接提交]