科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件调试与功能选择

调试与功能选择

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

调试与功能选择

作者:caimouse 来源:CSDN 2008年1月22日

关键字: 选择 功能 调试 Linux

  • 评论
  • 分享微博
  • 分享邮件
继续分析原来的代码,现在已经进入一个比较重要的函数dbginit(),因此这个函数相当复杂的功能调用。
 
/*
     * Init PMON and debug
     */
    cpuinfotab[0] = &DBGREG;
    dbginit(NULL);
第一行代码cpuinfotab[0]保存DBG寄存器值,主要包括32个通用寄存器和CP032寄存器,以及两个乘法除法这寄存器。
 
现在就来仔细地查看dbginit(NULL)的实现,代码如下:
 
/*
 * PMON2000 entrypoint. Called after initial setup.
 */
void
dbginit (char *adr)
{
    int memsize, freq;
    char   fs[10], *fp;
    char   *s;
 
/* splhigh();*/
 
    memsize = memorysize;
上面保存低端256M内存大小。
 
    __init(); /* Do all constructor initialisation */
上面调用初始化C++的构造函数初始化和全局的静态变量。
 
    SBD_DISPLAY ("ENVI", CHKPNT_ENVI);
    envinit ();
上面初始化环境变量。
 
#if defined(SMP)
    /* Turn on caches unless opted out */
    if (!getenv("nocache"))
       md_cacheon();
#endif
上面打开缓存。
 
 
    SBD_DISPLAY ("SBDD", CHKPNT_SBDD);
    tgt_devinit();
上面特定的主板初始化。
 
 
#ifdef INET
    SBD_DISPLAY ("NETI", CHKPNT_NETI);
    init_net (1);
#endif
上面选择网络初始化。
 
 
#if NCMD_HIST > 0
    SBD_DISPLAY ("HSTI", CHKPNT_HSTI);
    histinit ();
#endif
上面初始化是否缓存过去的命令。
 
 
#if NMOD_SYMBOLS > 0
    SBD_DISPLAY ("SYMI", CHKPNT_SYMI);
    syminit ();
#endif
上面选择是否设置符号表初始化。
 
 
#ifdef DEMO
    SBD_DISPLAY ("DEMO", CHKPNT_DEMO);
    demoinit ();
#endif
上面选择是否初始化演示功能。
 
 
    SBD_DISPLAY ("SBDE", CHKPNT_SBDE);
    initial_sr |= tgt_enable (tgt_getmachtype ());
上面保存状态寄存器。
 
 
#ifdef SR_FR
    Status = initial_sr & ~SR_FR; /* don't confuse naive clients */
#endif
    /* Set up initial console terminal state */
    ioctl(STDIN, TCGETA, &consterm);
上面初始化终端输出。
 
 
#ifdef HAVE_LOGO
    tgt_logo();
#else
    printf ("\n * PMON2000 Professional *");
#endif
    printf ("\nConfiguration [%s,%s", TARGETNAME,
           BYTE_ORDER == BIG_ENDIAN ? "EB" : "EL");
上面显示LOGO和显示字节顺序。龙芯是小端格式。
 
#ifdef INET
    printf (",NET");
#endif
#if NSD > 0
    printf (",SCSI");
#endif
#if NWD > 0
    printf (",IDE");
#endif
    printf ("]\nVersion: %s.\n", vers);
    printf ("Supported loaders [%s]\n", getExecString());
    printf ("Supported filesystems [%s]\n", getFSString());
    printf ("This software may be redistributed under the BSD copyright.\n");
上面显示提示信息。
 
    tgt_machprint();
上面显示厂家信息。
 
    freq = tgt_pipefreq ();
    sprintf(fs, "%d", freq);
    fp = fs + strlen(fs) - 6;
    fp[3] = '\0';
    fp[2] = fp[1];
    fp[1] = fp[0];
    fp[0] = '.';
    printf (" %s MHz", fs);
上面显示总线的频率。
 
 
    freq = tgt_cpufreq ();
    sprintf(fs, "%d", freq);
    fp = fs + strlen(fs) - 6;
    fp[3] = '\0';
    fp[2] = fp[1];
    fp[1] = fp[0];
    fp[0] = '.';
    printf (" / Bus @ %s MHz\n", fs);
上面显示CPU频率。
 
 
    printf ("Memory size %3d MB (%3d MB Low memory, %3d MB High memory) .\n", (memsize+memorysize_high)>>20,
       (memsize>>20), (memorysize_high>>20));
 
    tgt_memprint();
上面显示内存的大小。
 
 
#if defined(SMP)
    tgt_smpstartup();
#endif
上面选择多CPU的初始化。
 
 
    printf ("\n");
 
    md_clreg(NULL);
    md_setpc(NULL, (int32_t) CLIENTPC);
    md_setsp(NULL, tgt_clienttos ());
上面清空保存寄存器的变量,并保存新的PC值和堆栈值。
 
 
#ifdef AUTOLOAD
    s = getenv ("al");
    autoload (s);
#else
    s = getenv ("autoboot");
    autorun (s);
#endif
上面设置是否自动加载操作系统文件。
 
}
 
这个函数做了很多工作,下面要仔细地分析每个子函数实现的功能,才能理解后面所做的工作,否则也不知道后面会做些什么。又进入下一层函数分析它的实现。
 
首先来了解怎么样初始化C++的构函数和全局静态变量。仔细地看一下函数__init(),如下:
 
void
__init()
{
    static int initialized = 0;
 
    /*
     * Call global constructors.
     * Arrange to call global destructors at exit.
     */
    if (!initialized) {
       initialized = 1;
       __ctors();
    }
}
 
在这个函数里,先判断是否已经初始化全局函数和构造函数,如果没有初始化,就设置为已经初始化,接着调用函数初始化全局__ctors()函数。也许你会问,这些全局函数从那里来的呢?如果你去看看GCC的连接说明文件,就会发现有这个段在那里,因此这些全局函数是由编译器生成的,并不是由用户定义。如果不调用这些全局初始化函数,很多全局变量是没有定义的值,本来你编程时初始化为100的值,可能只是0或者任意的数值。现在又立即去看函数__ctors()的实现,如下:
static void
__ctors()
{
    void (**p)(void) = __CTOR_LIST__ + 1;
 
    while (*p)
       (**p++)();
}
 
由于GCC编译器会根据连接文件生成全局调用函数,下面就是连接文件相关内容,如下:
.ctors         :
 {
                __CTOR_LIST__ = .;
                LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 2)
               *(.ctors)
                LONG(0)
                __CTOR_END__ = .;
 }
 .dtors         :
 {
                __DTOR_LIST__ = .;
                LONG((__DTOR_END__ - __DTOR_LIST__) / 4 - 2)
               *(.dtors)
                LONG(0)
                __DTOR_END__ = .;
 }
 
编译器就会根据上面的连接脚本生成全局初始化函数和全局析构函数,并且每个函数入口是按照4字节的指针排列的。因此,在函数__ctors()里循环地调用所有函数运行一遍。后面析构函数相应也调用函数__dtors()来实现的。
 查看本文来源
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章