FreeNOS中C++源码部分相关类构造函数以及方法函数的初始化过程(六)

上节分析到从汇编代码正式跳转到C++代码,即kerne/Main.cpp中的kmain函数,接下来分析相关类构造函数以及方法函数的初始化过程。

kernel/Main.cpp文件代码如下:


#include <FreeNOS/Kernel.h>
#include <FreeNOS/Init.h>
#include <FreeNOS/Scheduler.h>

void kmain()
{
    /* Initialize kernel. */
    INITRUN(&initStart, &initEnd);
    
    /* Start scheduling. */
    scheduler->executeNext();
}

INITRUN(&initStart, &initEnd);部分是实现相关类构造函数以及方法函数的初始化过程的关键部分,展开该宏函数如下:

/** A memory address. */
typedef unsigned long Address;

/** Start of initialization routines. */
extern Address initStart;

/** Marks the end of all initialization functions. */
extern Address initEnd;

#define INITRUN(initStart,initEnd) \
    { \
	Address *i; \
	\
	for (i = (initStart); i < (initEnd); i++) \
	{ \
    	    (*(InitHandler **) i)(); \
	} \
    }

可以到分别调用地址处于initStart与initEnd的函数,initEnd是起始地址,initEnd是结束地址,那么函数地址处于中间段是怎么被放置二者之间呢?这个就又要看看kernel.ld文件的内容了:在这里插入图片描述
可以看到initStart与initEnd之间的部分是处于目标文件的.init* 段,而且是排序存放的。那么在目录查找.init符号:在这里插入图片描述
查看inlude/Init.h文件:
在这里插入图片描述
展开宏定义:
在这里插入图片描述
在这里插入图片描述
attribute((section(s))):需要了解一下gcc的__attribute__的编绎属性,__attribute__主要用于改变所声明或定义的函数或 数据的特性,它有很多子项,用于改变作用对象的特性。对代码段起作用子项section:
__attribute__的section子项的使用格式为:
attribute((section(“section_name”)))
其作用是将作用的函数或数据放入指定名为"section_name"输入段。

最后都是定义一个静态函数指针,不过一个是以类命名的的函数指正,一个只是普通函数函数指针,所以主要查看宏 INITFUNC(func,level)以及INITCLASS(class,func,level)是怎么使用的,现就源码举具体例子:
(1)INITFUNC(func,level)使用
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
将以上部分INITFUNC(constructors, CTOR)完全展开:在这里插入图片描述
分析来看就是 __initcall_constructors符号所知的函数指针constructors被放在了指定名为**".init2"输入段,所以目前在initStart与initEnd之间布局如下:
initStart ------>".init
"输入段开始地址
__initcall_constructors ------>constructors
initEnd ------>".init
"输入段结束地址

这样在kmain函数中:
INITRUN(&initStart, &initEnd);
就调用了__initcall_constructors (),即constructors(),完成了函数调用。
(2)INITCLASS(class,func,level)使用
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
同样可以试着展开宏,Memory是一个class,最后的结果是
void Memory::initialize()函数地址被放在了指定名为".init0"的输入段,那么最后
initStart与initEnd之间布局如下:
initStart ------>".init*“输入段开始地址
__initcall_Memory_initialize ------> Memory::initialize
__initcall_constructors ------>constructors
initEnd ------>”.init*"输入段结束地址

基本上相关类构造函数以及方法函数的初始化过程都是如此,而且共分为五个输入段
“.init0”、".init1"、".init2"、".init3"以及".init4":
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
剩余的就是追踪以上部分被引用的地方以及相关函数就可完全理解类构造函数以及方法函数的初始化过程,可以按指定输入段".init*"顺序排序查看函数调用,分析各部分源码的作用。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值