linux kernel的开始

原创 2016年08月31日 12:05:06
       现在学习看linux内核代码,一开始看一头雾水,不知道从那里开始,偶尔听一个同学说起内核就是一个while(1)循环,在看TPC/IP 内核协议栈时,经常看到内核的回调机制,结合自己看代码的经验,对内核结构猜测:内核是一个模型,这个模型具有良好的分层结构,在不同的模块里通过回调init完成注册,在推出时通过注册回调exit完成退出。
       在这里,内核使用了面向对象的思想。在我们讨论编程语言时,经常这样认为:C是面向过程的,C++是面向对象的语言。诚然,C++语言的语法上使用了面向对象的机制,C在语法上是面向过程的。是否可以这样认为:面向对象是一种编程思想,在我们使用C++时,编译器和C++语法帮助我们实现了对象的模型;而C则需要我们动脑筋抽象出模型,然后通过回调来实现不同的对象对应不同的FUNCTION。
       后来接触《Linux内核修炼之道》,才恍然大悟,内核的开始就是一个初始化得过程,呵呵,这一下就找到了内核的入口。在include/linux/init.h 里我们看到了内核初始化定义的数据结构。init.h头文件的开始就是__init数据结构的解释。

* These macros are used to mark some functions or
 * initialized data (doesn't apply to uninitialized data)
 * as `initialization' functions. The kernel can take this
 * as hint that the function is used only during the initialization
 * phase and free up used memory resources after
 *
 ......
这个宏(__init)用来表明一些函数或者初始化的数据(而不是未初始化得数据)是初始化函数。kernel把这些函数做为隐藏类型,仅仅在初始化阶段使用,初始化完成后,这些数据所用的内存资源会被释放。这就是宏(__init)的作用。接下来是三个列子。

第43行:
#define __init        __section(.init.text) __cold notrace
#define __initdata    __section(.init.data)
#define __initconst    __section(.init.rodata)
#define __exitdata    __section(.exit.data)
#define __exit_call    __used __section(.exitcall.exit)
是 __init 的定义  这句话的意思是 __init 类型的数据放在kernel文件的 (.init.text)。为什么会这样,和__section这个字段有关,请参考相关资料。在这里我猜测一下,kernel文件中有一个 init 的数据区,这个数据区分为text 区,data区,rodata区。 __init 修饰的是函数,所以放在text区,__initdata修饰数据,放在data区。

下面是《Linux内核修炼之道》的一段解释:“好像这里引出了更多的疑问,__attribute__是什么?Linux内核代码使用了大量的GNU C扩展,以至于GNU C成为能够编译内核的唯一编译器,GNU C的这些扩展对代码优化、目标代码布局、安全检查等方面也提供了很强的支持。而__attribute__就是这些扩展中的一个,它主要被用来声明一些特殊的属性,这些属性主要被用来指示编译器进行特定方面的优化和更仔细的代码检查。GNU C支持十几个属性,section是其中的一个,我们查看GCC的手册可以看到下面的描述
‘section ("section-name")'
   Normally, the compiler places the code it generates in the `text'
    section. Sometimes, however, you need additional sections, or you
need certain particular functions to appear in special sections.
   The `section' attribute specifies that a function lives in a
   particular section. For example, the declaration:

     extern void foobar (void) __attribute__ ((section ("bar")));

   puts the function ‘foobar' in the ‘bar' section.

   Some file formats do not support arbitrary sections so the
   ‘section' attribute is not available on all platforms. If you
   need to map the entire contents of a module to a particular
   section, consider using the facilities of the linker instead.
通常编译器将函数放在.text节,变量放在.data或.bss节,使用section属性,可以让编译器将函数或变量放在指定的节中。那么前面对__init的定义便表示将它修饰的代码放在.init.text节。连接器可以把相同节的代码或数据安排在一起,比如__init修饰的所有代码都会被放在.init.text节里,初始化结束后就可以释放这部分内存。”
#ifndef MODULE
#ifndef __ASSEMBLY__
这是两个比较常见的宏:
下面解释下它的作用。
__ASSEMBLY__用于汇编和c代码共享的头文件
源程序==》预处理器(cpp)==》编译器(ccl)==》汇编器(as)==》链接器(ld)==》可执行文件
有些定义cc1可以辨认,而as汇编器不能辨认。汇编程序不需要编译器
cpp会根据源文件是否是汇编程序(.s)来选择正确的定义
__ASSEMBLY__就是为了解决这样的问题。
MODULE 宏随后解释。
在273行:
#else /* MODULE */
/* Don't use these in modules, but some people do... */
#define early_initcall(fn)        module_init(fn)
#define core_initcall(fn)        module_init(fn)
#define postcore_initcall(fn)        module_init(fn)
#define arch_initcall(fn)        module_init(fn)
#define subsys_initcall(fn)        module_init(fn)
#define fs_initcall(fn)            module_init(fn)
#define device_initcall(fn)        module_init(fn)
#define late_initcall(fn)        module_init(fn)

#define security_initcall(fn)        module_init(fn)

/* Each module must use one module_init(). */
#define module_init(initfn)                    \
    static inline initcall_t __inittest(void)        \
    { return initfn; }                    \
    int init_module(void) __attribute__((alias(#initfn)));
就是MODULE的定义:int init_module(void) __attribute__((alias(#initfn))); 在MODULE模式下,init_modele 的数据是放在alias(#initfn)这个区。上边是相关宏的定义,所有的数据区都被放在这里了。在156行以后,是#ifndef MODULE 模式,这两种情况下,数据在内核中的位置是不一样的。这就对应了驱动的两种模式,编译进内核和作为模块安装。



<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>
阅读(417) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:在frambuffer 下画图

给主人留下些什么吧!~~
评论热议
版权声明:本文为博主原创文章,转载请注明出处。

打开Linux内核启动早期的log

 打开Linux内核启动早期的log 有时会遇到当在u-boot中执行完bootm后,打印出start kernel后串口就没有再输出任何信息了。此时就需要打开内核早期的log: ...
  • lieye_leaves
  • lieye_leaves
  • 2017年08月22日 22:31
  • 361

linux内核之块设备二---真正派发请求request

触发请求request派发的时机: 重新申请一个请求失败时将一个带有unplug标记的bio添加到请求队列时将请求添加调度器的调度队列,达到了unplug阈值时unplug定时时间到,周期性 ...
  • revoer001
  • revoer001
  • 2016年07月23日 13:09
  • 1597

linux kernel启动流程

来源:Linux社区  作者:ce123_zhouwei 本文写的真心不错,层次清晰,内容详略得当,值得一阅,谨做笔记使用。 Linux内核启动流程    arch/arm/kernel/...
  • wyz649296016
  • wyz649296016
  • 2016年08月06日 11:46
  • 839

《linux 内核完全剖析》 fork.c 代码分析笔记

fork.c 代码分析笔记 verifiy_area long last_pid=0; //全局变量,用来记录目前最大的pid数值 void verify_area(void...
  • u011368821
  • u011368821
  • 2014年05月08日 12:13
  • 2002

linux kernel 一些比较好的网站

Original url: http://www.xuebuyuan.com/830779.html http://www.kernel.org The Linux Kernel A...
  • junmuzi
  • junmuzi
  • 2017年01月04日 10:14
  • 487

什么是linux kernel?有什么作用?

说到kernel就得先明白什么是操作系统,什么是kernel?什么是操作系统?他们是什么关系?貌似这个问题很大框,答案挺多,以前总以为自己是明白的,但当面试时被问到还真不知道怎么样才是正确的答案,现在...
  • u014070965
  • u014070965
  • 2014年03月15日 14:07
  • 2557

如何阅读linux内核源码

   一.核心源程序的文件组织:  1.Linux核心源程序通常都安装在/usr/src/linux下,而且它有一个非常简单的编号约定:任何偶数的核心(例如2.0.30)都是一个稳定地发行的核心,而任...
  • yyaong_520
  • yyaong_520
  • 2010年04月05日 09:11
  • 1484

Linux Kernel patch升级

kernel 2.6.32.13版本的kernel,现要升级到2.6.32.16。 1) kernel.org上下载patch-2.6.32.13.bz2和patch-2.6.32.16.bz2两个p...
  • sehrich
  • sehrich
  • 2010年07月16日 09:47
  • 2441

Linux kernel development

linux
  • ingwfj
  • ingwfj
  • 2017年01月06日 14:53
  • 1267

Linux kernel configuration

Linux kernel configuration
  • ztguang
  • ztguang
  • 2016年07月30日 12:21
  • 715
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:linux kernel的开始
举报原因:
原因补充:

(最多只允许输入30个字)