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 kernel源代码

从何处开始阅读源代码 像Linux内核这样庞大而复杂的程序看起来确实让人望而生畏,它象一个很大的球,没有起点和终点。在读源代码的过程中,你会遇到这样的情况,当读到内核的某一部分时又会涉及到其它更多的...

Mastering Linux Kernel Development epub

  • 2017年10月31日 22:34
  • 2.82MB
  • 下载

Linux kernel U盘识别流程

一、正常USB枚举及断开的log正常U盘插入和拔掉Kernel log的打印消息如下:[ 220.836836] usb 2-1: new high-speed USB device number ...

Linux Kernel 四库全书

  • 2017年10月31日 11:30
  • 27.76MB
  • 下载

linux kernel list的应用

  • 2017年06月28日 08:45
  • 6KB
  • 下载

Linux Kernel 学习笔记2:模块参数

在用户态下编程可以通过main()来传递命令行参数,而编写一个内核模块则可通过宏module_param()来传递命令行参数. 先来看看这个宏的定义(Linux-4.4.0-37) #define m...

Linux Kernel Development(3rd) 无水印pdf

  • 2017年09月27日 10:24
  • 2.03MB
  • 下载

linux kernel 源码剖析 共享内存部分

  • 2017年09月09日 18:18
  • 1.24MB
  • 下载

Linux kernel多线程的几种实现

驱动开发中常常会启动几个内核线程,在整个驱动生命周期期间执行某些操作,比如USB驱动的控制线程,一直等待SCSI命令,没有命令的话睡眠,有命令的话就唤醒线程,解析执行相关的命令。还有USB驱动中的扫描...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:linux kernel的开始
举报原因:
原因补充:

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