zoukankan      html  css  js  c++  java
  • 全面解析Linux 内核 3.10.x

    万事开头难 - 如何开始?

    人总是对未知的事物充满恐惧!就像航海一样,在面对危难的时候,船员和船长是一样心中充满恐惧的!只是船员始终充满恐惧,而船长却能压抑恐惧并从当前找出突破口! 
    我没有船长之能,但也算入行两年的老船员,我会追随船长一起寻找突破口!而内核如此庞然大物不知从何入手这真的很正常,那么应该的入口在哪里?其实我也不知道,一千个读者就有一千个哈姆雷特。每个人都入口的理解都不一样,有人说是必须有着良好的C编程经验,有人说必须有着对Linux发行版等必要的操作经验,也有的人说一定要数据结构理解的很好,还有的人说你必须的对各种架构的汇编了如指掌!眼花撩乱的知识你又掌握了多少呢?

    我列出三点

    1.必须有着良好的C语言理解能力,尤其是指针(灵魂嘛) 
    2.数据结构确实的能看懂,尤其是链表 
    3.一定要有着非常浓厚的兴趣,不成魔,不成活 
    第3点尤其最重要,因为兴趣才是王道

    假设你已经对上述内容有了一定的了解或者已经是个老手了!想急需的去更深入的研究内核! 
    那么我们就开始吧!

    1. 你应该了解内核源码树

    顶层目录
    
    ├── arch            --  体系架构相关代码,内核支持市面上所有的主流架构以及N多种CPU
    ├── block           -- 块设备子系统
    ├── crypto          -- 加密解密库函数
    ├── Documentation   -- 说明文档
    ├── drivers         -- 设备驱动
    ├── firmware        -- 第三方设备固件
    ├── fs              -- 文件系统子系统(VFS)
    ├── include         -- 公共头文件
    ├── init            -- 启动初始化子系统(如挂载initrd)
    ├── ipc             -- 进程通信子系统
    ├── Kbuild          -- 顶层链接文件
    ├── Kconfig         -- 顶层配置配置
    ├── kernel          -- 内核核心代码(基本与架构无关,包括调度子系统)
    ├── lib             -- 公共LIB库函数
    ├── Makefile        -- 顶层编译文件
    ├── mm              -- 内存管理子系统
    ├── net             -- 不包括网络设备驱动的网络子系统
    ├── README          -- 你懂得
    ├── samples         -- Demo 代码
    ├── scripts         -- 编译脚本以及工具
    ├── security        -- 模块安全相关(SELinux)
    ├── sound           -- 音频驱动子系统
    ├── tools           -- 内核辅助工具
    ├── usr             -- 用户程序(目前只有一个用于initramfs的cpio打包程序)
    └── virt            -- 虚拟化相关
    ├── REPORTING-BUGS  -- Bug 上报流程
    ├── MAINTAINERS     -- 主要维护者(向社区致敬)
    ├── CREDITS         -- 贡献者(请牢记伟大的程序员)
    

    内核真是太庞大了,目前这个版本的代码量已经到了几百万行之多,那么问题来了,这么多的内容我们应该如何取舍?

    2. Linux Kernel 核心功能一览

    Linux 核心功能分为五大子系统(进程管理,内存管理,虚拟文件系统,网络子系统,进程间通信)! 
    Ps.下面是网上找了一张图片 

    1. Process Mangement称作进程管理or进程调度。主要负责管理CPU资源的平衡调度,抢占,异常入口等的管理。主要为了确保各个进程尽量以公平的方式来对CPU执行调度!Ps.这里其实就要说到优先级等相关内容!这部分是必须要研究的一部分!
    2. Memory Manager称作内存管理。主要负责管理内存资源的分配以及配额,确保各个进程任务可以放心去共享使用当前的内存资源。此外,内存管理也会提供虚拟内存机制处理,该机制可以让进程使用多于系统可用Memory的内存(也就是内存地址转换),不用的内存会通过文件系统保存在外部非易失存储器中,需要使用的时候,再取回到内存中。这部分也是必须要研究的一部分!
    3. IPC称作进程间通信。它主要负责Linux系统中进程之间的通信,这里跟硬件无关! 这部分无需多说,必须研究!
    4. Network称作网络子系统,主要负责管理系统的网络设备,并实现多种多样的网络标准以及提供各种各样协议的基本协议栈。这部分如果从事网络领域可以仔细研究(难点也是在于协议栈),这部分可以了先了解!
    5. Virtual File System称作虚拟文件系统。Linux内核将不同功能的外部设备,例如Disk设备(硬盘、磁盘、NAND Flash、Nor Flash等)、输入输出设备、显示设备等等,抽象为可以通过统一的文件操作接口(open、close、read、write等)来访问。这部分如果从事存储就必须要研究啦!它往往是结合块设备驱动来进行的!
    6. SELinux/AppArmor号称最杰出的操作系统安全子系统,最早由NSA(美国国家安全局)来领导并研发的一套安全子系统!这部分内容如果暂时可以先了解下!

    Ps…对了,还忘了说一个非常非常重要的核心,那就是体系架构,因为我当前是Mips,所以首先的熟悉MIPS架构中的一些最基本的处理方式,并且内核中有很多关于MIPS的汇编以及GUN混合MIPS的伪汇编,都需要去啃啊,瞬间好头大!深吸一口气,慢慢来吧!这部分内容作为整体穿插的时候在进行脑补吧!!!!

    3.Makefile

    好吧,下一节就要进行实战了,这里先脑补一下Makefile. 
    Makefile作为构建内核的引线,穿插在各个目录中!那么对它的语法先简单的了解下! 
    基本的 make流程 其实是根据文件的时间戳来更新(读取Makefile) 文件的编译工作 
    从一个样例来说明Makefile.

        main:main.o name.o age.o
               gcc main.o name.o age.o -o main
        main.o:main.c
               gcc -c main.c -o main.o
        name.o:name.c
               gcc -c name.c -o name.o
        age.o:age.c
               gcc -c age.c -o age.o
        clean:
              rm *.o main  

    基本格式为: 目标生成文件名:源文件 
    生成过程(得到结果) 
    clean 作为方便的清除Makefike生成的编译文件 
    看上述的主文件 
    main.c

        #include <stdio.h>                                                                     
        extern void name();
        extern void age();
    
        int main()
        {
             name();
             age();
    
             return 0;
        }       
        name.c
        #include <stdio.h>                                                                     
    
        void name()
        {
             printf("My name is Xw. 
    ");
        }
    
        age.c
        #include <stdio.h>                                                                     
    
        void age()
        {
             printf("My age is 22........
    ");
        }
    
    • 直接编译可产生结果。 

    杂种Shell + Makefile的演变 
    当我们的可编译文件越来越多时候,那么即时可能你少了一个.o文件那也直接导致程序崩溃。 
    所以这个时候我们的杂种Shell(其实严谨的说不是shell相似而已)就有用了。我们大可以用一个变量去代替你的源文件、也可以代替我们的编译器。如下

         CC=gcc                           //变量代替你的编译器                                                      
         OBJS=main.o name.o age.o       //源文件
         main:$(OBJS)
                 $(CC) $^ -o $@
         main.o:main.c
                 $(CC) -c $^ -o $@
         name.o:name.c
                 $(CC) -c $^ -o $@
         age.o:age.c
                 $(CC) -c $^ -o $@
         clean:
                 rm *.o main
    
    • 没有出现的<<这些命令以后会用到。分别先介绍一下@ 表示目标文件的完整名称 如上述main main.o name.o age.o等 

    main.omain.c表示所有不重复的依赖包名称以空格隔开如上述main.omain.c分别可以做依赖包、因为依赖和被依赖仅仅是方向不一样。其实是可以转化的。当然上述还可以写成。(CC) -c OBJSomain.oOBJS−omain.o<表示第一个依赖包名称

    Ps.上述仅仅是Makefile 最基本的使用,在内核里完全是另外一回事,但是基本语法是一样的!

    *下一节我们就开始内核的Makefile以及其它编译规则的分析*

  • 相关阅读:
    WPF XAML之bing使用StringFormat
    C#程序以管理员权限运行
    注册表REG文件编写大全
    linux 的基本操作(编写shell 脚本)
    linux的基本操作(正则表达式)
    linux的基本操作(shell 脚本的基础知识)
    linux的基本操作(RPM包或者安装源码包)
    linux的基本操作(文件压缩与打包)
    linux的基本操作(文本编辑工具vim)
    linux的基本操作(磁盘管理)
  • 原文地址:https://www.cnblogs.com/zhugeanran/p/9108496.html
Copyright © 2011-2022 走看看