1、《Linux内核分析》总结linux
(一)计算机是如何工做的git
1.存储程序计算机工做模型程序员
2. X86CPU的寄存器:通用寄存器、段寄存器、标志寄存器等。算法
3.计算机的汇编指令安全
(1)movl指令:服务器
注意:AT&T汇编格式与Intel汇编格式略有不一样,Linux内核使用的是AT&T汇编格式。网络
(2)其余指令数据结构
堆栈是向下增加的,有一个基址ebp指向堆栈栈底并发
注意:*是指这些指令是伪指令,程序员不能直接修改这些,即eip寄存器不能被直接修改,只能经过特殊指令间接修改。框架
4.将C代码编译成汇编代码
(1)函数调用堆栈是由逻辑上多个堆栈叠加起来的
(2)函数的返回值默认使用eax寄存器存储返回给上一级函数
(3)使用命令编译成汇编代码:gcc –S –o main.s main.c -m32
(二)操做系统是如何工做的
1. 堆栈——堆栈式C语言程序运行时必须的一个记录调用路径和参数的空间。包括:函数调用框架;传递参数;保存返回地址(如eax);提供局部变量空间
2. 堆栈寄存器:esp 堆栈指针和ebp 基址指针(在C语言中表示当前函数调用基址)
3. 堆栈操做:push栈顶指针减小4个字节(32位)和pop 栈顶指针增长4个字节
4. 参数传递与局部变量
(1)创建框架(至关于 call 指令)
push %ebp
movl %esp,%ebp
(2)拆除框架(至关于 ret 指令)
movl %ebp,%esp
pop %ebp
函数返回时必定会拆除框架,创建和拆除是一一对应的。
(3)传递参数
在创建子函数的框架以前,局部变量的值保存在调用者堆栈框架中,因此在子函数框架创建以前能够采用变址寻址的方式将变量值入栈。
!函数的返回值经过eax寄存器传递
(三)构造一个简单的Linux系统MenuOS
1. 计算机三个法宝:存储程序计算机、函数调用堆栈、中断
2. 操做系统两把宝剑:中断上下文的切换(保存现场和恢复现场)以及进程上下文的切换
3. 总结:rest_init为0号进程,一直存在。0号进程建立了1号进程kernel_init,还建立了其余的服务线程。即道生一(start_kernel....cpu_idle),一辈子二(kernel_init和kthreadd),二生三(即前面0、1和2三个进程),三生万物(1号进程是全部用户态进程的祖先,2号进程是全部内核线程的祖先)。
Linux在无进程概念的状况下将一直从初始化部分的代码执行到start_kernel,而后再到其最后一个函数调用rest_init。
从rest_init开始,Linux开始产生进程,由于init_task是静态制造出来的,pid=0,它试图将从最先的汇编代码一直到start_kernel的执行都归入到init_task进程上下文中。在rest_init函数中,内核将经过下面的代码产生第一个真正的进程(pid=1)。而后init_task变为一个idle task,init_idle函数的第一个参数current就是&init_task,在init_idle中将会把init_task加入到cpu的运行队列中,这样当运行队列中没有别的就绪进程时,init_task(也就是idle task)将会被调用,它的核心是一个while(1)循环,在循环中它将会调用schedule函数以便在运行队列中有新进程加入时切换到该新进程上。
(四)扒开系统调用的三层皮
1.用户态和内核态
Intel x86 CPU有四种不一样的执行级别0—3,Linux只是用了期中的0级和3级分别表示内核态和用户态。
2.理解中断处理的完整过程:中断信号(int指令)完成:保存cs:eip的值、当前堆栈段栈顶和当前标志,同时加载了当前中断信号或是系统调用的相关联的中断服务入口到cs:eip里面,把当前对战段和esp也加载到CPU里面。
SAVE ALL完成后若没有发生调度,则接着执行RESTORE_ALL;若发生进程调度,则当前的状态会暂时的保存在系统里面,当下一次发生进程调度切换到当前进程时再接着执行完毕。
3. 系统调用的三个层次
系统调用的三个层次依次是:xyz函数(API)、system_ call(中断向量)和 sys_ xyz(中断服务程序)。
4. 总结:
在Linux系统中是经过激活0x80中断来触发系统调用的,须要调用的系统调用号实现赋值给eax存储器,若是有传入参数可赋值给ebx寄存器,若是多于1个则按顺序赋值给ebx、ecx、edx、esi、edi、ebp,若是超过6个则经过指针变量指向另外一片堆栈区,若是无参数传入则赋值为0。
虽然Intel X86 CPU有4种执行级别0~3,可是在Linux系统中仅使用了0和3级,分别表示内核态和用户态。一些涉及底层、硬件、核心的操做必须在内核态下才容许执行,为操做系统程序和驱动程序专享,普通程序仅能执行在用户态下。若是普通程序须要涉及内核态的操做,就须要经过系统调用来实现。这样作的好处是屏蔽平台相关操做下降了软件开发难度,加强了系统安全性,使程序具备更好的移植性(Linux系统及其余Unix系统遵循统一标准,系统调用基本同样)。
(五)进程额管理和进程的建立
操做系统内核三大功能:进程管理(核心)、内存管理和文件系统。
1.Linux经过复制父进程来建立一个新进程,经过调用do_fork来实现。
2.Linux为每一个新建立的进程动态地分配一个task_struct结构。
3.为了把内核中的全部进程组织起来,Linux提供了几种组织方式,其中哈希表和双向循环链表方式是针对系统中的全部进程(包括内核线程),而运行队列和等待队列是把处于同一状态的进程组织起来。
4.fork()函数被调用一次,但返回两次。
(六)可执行程序的装载
1.可执行程序过程:先预处理.cpp,在编译成汇编代码.s到目标代码.o,再连接成可执行文件,加载到内存中执行。
2.可执行文件加载到内存中开始执行的第一行代码,0X8048X00为实际的入口。
3. 动态连接分为可执行程序装载时动态连接和运行时动态连接。
4. do_ execve调用do_ execve_ common,do_ execve_ common主要依靠exec_ binprm,其中重要的函数:search_binary_handler(bprm)。
(七)进程的切换和系统的通常执行过程
1. 进程调度算法——每一个进程对CPU、I/O等资源需求不同。
2. 进程调度(schedule()函数实现)的时机:
注意:用户态进程只能被动调度,内核线程是只有内核态没有用户态的特殊进程。
3. 操做系统(任何计算机系统都包含一个基本的程序集合)有两个目的:
4. 本周主要理解Linux中进程调度与进程切换过程。进程调度是按必定的策略动态地把处理机分配给处于就绪队列中的某一个进程,以使之执行。而进程切换是从正在运行的进程中收回处理器,而后再使待运行进程来占用处理器。实质上就是把进程存放在处理器的寄存器中的中间数据找个地方存起来,从而把处理器的寄存器腾出来让其余进程使用。
2、《Linux内核设计与实现》总结
(一)第一章 Linux内核简介
Linux系统的基础是内核、C库、工具集和系统的基本工具。
1.操做系统:整个系统中负责完成最基本功能和系统管理的部分。
2.内核(操做系统的内在核心,通常处于系统态):
由响应中断的中断服务程序;管理多个进程,分享处理器时间调度程序;管理进程地址空间的内存管理程序;网络、进程间通讯等系统服务程序组成。
3.内核空间:系统态和被保护起来的内存空间
4.系统调用:应用程序与内核通讯。应用程序经过系统调用界面陷入内核是应用程序完成工做的基本行为方式。
6.Unix内核一般须要硬件系统提供页机制(MMU)以管理内存,这样能够增强对内存空间的保护,并能够保证每一个进程都运行于不一样的虚地址空间上。
7.单内核与微内核比较:
(1)单内核——以单个静态二进制文件形式存放于磁盘中,全部内核服务在一个大内核地址空间上运行。
特色:内核能够直接调用函数,简单并性能高。但一个功能的崩溃会致使整个内核没法使用。
(2)微内核——内核按功能被划分红各个独立的过程。每一个过程叫作一个服务器。全部服务器独立并运行在本身的地址空间上。
特色:经过消息传递处理为内核通讯,采用进程间通讯(IPC)机制。安全。一个服务器失效不会影响其余服务器。内核各个服务之间的调用涉及进程间的通讯,比较复杂且效率低。
8.Linux内核总结:
为单内核,但具有微内核的一些特征:模块化设计、抢占式内核、支持内核线程、动态装载内核模块。同时避微内核设计上的性能缺陷:让全部事情运行在内核态,直接调用函数,无需消息传递。支持动态加载内核模块;支持对称多处理(SMP);内核能够抢占(preemptive),容许内核运行的任务有优先执行的能力;不区分线程和进程;提供具备设备类的面向对象的设备模型、热插拔事件,以及用户空间的设备文件系统(sysfs)。
(二) 第二章 从内核出发
1.使用Git(管理内核源码的分布式控制系统)获取最新提交到Linus版本树的一个副本:
$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
2.安装内核源代码
两种形式:GNU zip(gzip)(运行:$ tar xvzf linux-x.y.z.tar.gz)和bzip2(运行:$ tar xvjf linux-x.y.z.tar.bz2)。
3. 配置内核(关于make与config)
配置编译过程:
• make config:遍历全部配置项,并让用户选择
• make deconfig:基于默认的配置
• make oldconfig:先将/boot目录下的配置文件写进.config文件中,采用的是注释的形式写进新增长的功能。
• zcat /proc/config.gz > .config:配置选项CONFIG_IKCONFIG_PROC把完整的压缩过的内核配置文件存放在/
proc/config.gz中,再次编译时能够方便地克隆当前的配置。
• make:默认的Makefile自动化编译。
4.减小编译的垃圾信息;衍生多个编译做业
5.安装新内核——把全部已编译的模块安装到正确的主目录/lib/modules下:% make modules_install。编译时在内核代码树的根目录下建立一个System.map文件(符号对照表),用来将内核符号与它们的起始地址对应起来。
6.同步和并发
• Linux是抢占多任务操做系统
• 内核支持对称多处理器系统(SMP)
• 中断是异步到来的
• Linux内核能够抢占
经常使用的解决竞争的办法是自旋锁和信号量
(三) 第三章——进程管理
1.进程就是处于执行期的程序(目标码存放在某种存储介质上),不只局限于一段可执行程序代码,还包含其余资源,如打开的文件、挂起的信号、内核内部数据等。提供两种虚拟机制:虚拟处理器和虚拟内存。
2.线程(执行线程)是在进程中活动的对象,拥有独立的程序计数器、进程栈和一组进程寄存器。注意:内核调度的是线程而不是进程!
3.系统调用经过复制一个现有进程来建立一个全新的进程。调用fork()的进程为父进程,新产生的进程称为子进程。fork()系统调用从内和返回两次:一次回到父进程,一次回到新产生的子进程。
4. 共有五种进程状态:
5.进程建立:写时拷贝——fork()——vfork()
6.进程终结:删除进程描述符——孤儿进程形成的进退维谷
(四)第四章——进程调度
1.多任务系统分为两类:非抢占式多任务和抢占式
2.策略:调度策略一般在两个矛盾的目标中间寻找平衡:进程响应迅速(响应时间短)和最大系统利用率(高吞吐量)。
3. 进程优先级
在某些系统中,优先级高的进程使用的时间片也比较长。调度程序老是选择时间片未用尽并且优先级最高的进程运行。用户和系统均可以经过设置进程的优先级来影响系统的调度。
Linux采用了两种不一样的优先级范围——nice值和实时优先级值。
(1) nice值,范围是-20到19,数值越大优先级越低,默认值为0。Linux中,nice值则表明时间片的比例。能够经过ps-el命令查看系统中的进程列表,结果中标记NI的一列就是进程对应的nice值。
(2) 实时优先级值,默认0到99,数值越大优先级越高。任何实时进程的优先级都高于普通的进程。
4.公平调度——CFS中,任何进程所得到的处理器时间是由它本身和其余全部可运行进程nice值的相对差值决定。任何nice值对应的绝对时间是处理器的使用比。
5.调度的实现——CFS相关代码四个组成部分:时间记帐、进程选择、调度器入口和睡眠和唤醒。
6.用户抢占(会检查need_ resched标志)发生时机:
7.内核抢占发生时机:
8.实时调度策略
linux 提供两种实时调度策略SCHED_FIFO和SCHED_RR。
这两种算法实现的都是静态优先级。Linux实时调度算法是软实时工做方式——内核调度进程,尽可能使进程在它的限定时间到来前运行,但内核不能保证可以总能知足。
实时优先级范围是0到MAX_RT_PRIO减1。默认状况下,MAX_RT_PRIO为100,nice值从-20到19直接对应的是100到139的实时优先级范围。
(五)第五章——系统调用
重点——Linux系统调用的规则和实现方法。
1.如何定义一个系统调用:asmlinkage long sys_getpid(void)
2.Linux系统调用执行快,两个缘由:
3.通知内核的机制是靠软中断实现的
4.x86-32系统中,参数传递时ebx,ecx,edx,esi,edi按顺序存放前五个参数。给用户空间的返回值也经过寄存器传递。在x86系统上,它存放在eax寄存器中。
5.系统调用上下文
• 内核在执行系统调用的时候处于进程上下文。
• 在进程上下文中,内核能够休眠而且能够被抢占。
• 当系统调用返回的时候,控制权仍在system_call()中,它最终会负责切换到用户空间,并让用户进程继续执行下去。
(六)第七章 连接
1.静态连接:连接器将重定位目标文件(relocatable object files)组合成一个可执行目标文件。cpp(c previous processor,C预处理器);ccl(C编译器);as(汇编器)。
为了建立静态连接,连接器完成两个主要任务:
2.目标文件有三种形式:
3.重定位由两步组成:
4.注意:静态连接与动态连接的区别——静态连接是把程序所须要的库代码和数据拷贝和嵌入到引用它们的可执行文件中;而动态连接是全部引用该库的可执行文件文件共享这个.so(dll)文件中的代码和数据。
5.动态连接器经过执行下面的重定位完成连接任务:
学习感想与体会:
从这学期还没开学开始学习云课堂《Linux内核分析》,跟着孟老师一步一步了解Linux内核,到如今半个学期已通过去,又对课本《Linux内核设计与实现》的一些章节,搭配着视频进行学习巩固。时间感受过得很快。但同时也学到了很多知识。
首先,经过这门课的学习,加深了我对操做系统理论的理解,知道了Linux系统是如何工做的,如何经过代码阅读、调试去跟踪验证Linux系统的运行机制。其次,Linux做为一个极其成功的操做系统,其内核纷繁复杂、博大精深,我我的学习起来也是至关困难。虽然完成了网课、看了课本,孟老师也讲得不错,但我仍是感受本身刚刚开始学习,并且须要在深刻挖掘的东西还有不少不少。
经过半个学期的学习,我认为重要的不是学习到了多少内核代码(其实也很重要);但更重要重要的是学习方法,即从何处着手学习Linux内核,例如:如何调试内核、如何看懂内核中的汇编代码,如何分析系统调用等。总之,学习尚未结束,还有半个学期,继续加油~