Chinaunix首页 | 论坛 | 博客
  • 博客访问: 379483
  • 博文数量: 715
  • 博客积分: 40000
  • 博客等级: 大将
  • 技术积分: 5005
  • 用 户 组: 普通用户
  • 注册时间: 2008-10-13 14:46
文章分类

全部博文(715)

文章存档

2011年(1)

2008年(714)

我的朋友

分类:

2008-10-13 16:34:14

//
// 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!


--------------------next---------------------

阅读(158) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~