Linux_总结

具体博客链接

一、计算机是如何工作的

存储程序计算机工作模型

  • 冯诺依曼体系结构

    • 从硬件角度来看:CPU和内存,由总线连接,CPU中有一个名为IP的寄存器,总是指向内存的某一块:CS,代码段,执行命令时就取IP指向的一条指令,然后IP自加1,就指向下一条指令。
    • 从程序员角度来看:即存储程序计算机,内存存储数据和指令,CPU就是一个for循环,总是在执行下一条指令,CPU负责解释和执行这些指令。

X86汇编基础

  • CPU寄存器

    • 通用寄存器+段寄存器+标志寄存器
  • X86汇编指令
    • mov指令:b,w,l,q分别代表8位,16位,32位,64位
    • 寻址方式:寄存器寻址,立即数寻址,直接寻址,间接寻址,变址寻址
    • 汇编指令:push,pop,call,ret
    • leave
  • 分析汇编指令片段

汇编一个简单的C程序分析其汇编指令执行过程

  • 汇编一个简单的C程序
  • C程序和对应的汇编指令
  • 完整汇编程序执行过程分析

二、操作系统是如何工作的

函数调用堆栈

  • 计算机三大法宝

    • 存储程序计算机工作模型
    • 函数调用堆栈
    • 中断
  • 深入理解函数调用堆栈
    • 函数调用框架
    • 传递参数
    • 保存返回地址
    • 提供局部变量空间
  • 堆栈相关寄存器:esp堆栈指针ebp基址指针,记录当前函数调用基址
  • 堆栈操作:push,pop
  • cs:eip:总是指向下一条的指令地址,执行call的时候,保存下一条指令地址到栈顶,然后cs:eip指向调用函数入口地址。
  • 参数传递与局部变量

借助Linux内核部分源代码模拟存储程序计算机工作模型及时钟中断

  • mykernel实验背后涉及的思想
  • 利用mykernel实验模拟计算机硬件平台
  • 由CPU和内核代码共同实现了保存现场和恢复现场

在mykernel基础上构造一个简单的操作系统内核

  • C代码中嵌入汇编代码的写法
  • 一个简单的操作系统内核源代码
    • mypcb.h:头文件
    • mymain.c: 内核初始化和进程的启动
    • myinterrupt.c:进程的切换
  • 运行这个精简的操作系统内核

三、构造一个简单的Linux系统MenuOS

Linux内核源代码简介

  • 操作系统两把宝剑

    • 中断上下文的切换
    • 进程上下文的切换
  • Linux内核源代码

构造一个简单的Linux系统

  • 构造一个简单的Linux系统MenuOS

    • qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img

      • qemu:启动一个虚拟机平台
      • -kernel:给一个内核,操作系统
      • -initrd:驱动所需的硬盘
      • rootfs.img:放一个可执行文件由menuOS源代码编译成的init

跟踪调试Linux内核的启动过程

  • 使用gdb跟踪调试Linux内核的方法

    • qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S

      • -S freeze CPU at startup (use ’c’ to start execution)指在CPU初始化之前(刚启动的时候)将其冻结
      • -s shorthand for -gdb tcp::1234 指在1234这个端口上创建的gdb server,若不想使用1234端口,则可以使用-gdb tcp:xxxx来取代-s选项
    • gdb
    • (gdb)file linux-3.18.6/vmlinux # 在gdb界面中targe remote之前加载符号表
    • (gdb)target remote:1234 # 建立gdb和gdbserver之间的连接,按c 让qemu上的Linux继续运行
    • (gdb)break start_kernel # 断点的设置可以在target remote之前,也可以在之后
      • 符号:全局函数名,全局变量名,汇编时没有,不需要符号只是一个地址,但调试时需要,所以有符号表:符号与在内存中地址的一一对应。
  • 简单分析一下start_kernel
    • 全局变量init_task,即手工创建的PCB,0号进程即最终的idle进程
    • trap_init涉及到中断,初始化一些中断向量
    • mm_init:内存管理模块初始化
    • sched_init:调用进程调度初始化
    • rest_init中:
      • kernel_init:创建1号进程
      • 第一个用户态进程:init_process,1号进程,找默认路径下的程序作为1号进程
      • kthreadd:内核线程,用来管理系统资源
      • 当系统没有进程需要执行时就调度idle进程,即0号进程,一直存在。

四、系统调用

用户态、内核态和中断

  • 用户态&内核态(CPU执行级别)

    • 内核态:高级别执行,可以使用特权指令,访问任意的物理地址。对应x86 0级
    • 用户态:低级别执行,代码范围受到限制。对应x86 3级(x86CPU有0-3四个级别)
  • 如何区分用户态&内核态?
    • 0xc0000000以上的地址只能在内核态下访问
    • 0x00000000-0xbfffffff两种状态都行
  • 中断处理是从用户态进入内核态主要的方式
    • 从用户态进入内核态:必须保存用户态的寄存器上下文
    • 中断/int指令在堆栈上保存寄存器的值:用户态/内核态栈顶地址(ss:esp)、状态字(eflags)、cs:eip值(内核态时指向中断服务程序入口)

系统调用概述

  • 系统调用的意义

    • 用户不管硬件编程
    • 提高系统安全性
    • 用户程序可移植
  • API和系统调用
    • API:应用编程接口,是一个函数定义
    • 系统调用:通过软中断向内核发出明确请求
    • 不是每个API都对应一个特定的系统调用
  • 应用程序、封装例程、系统调用处理程序、系统调用服务例程之间的关系
  • 系统调用三层皮:
    • API(xyz)
    • 中断向量(system_call)
    • 中断服务程序(sys_xyz)

使用库函数API和C代码中嵌入汇编代码触发同一个系统调用

  • 使用库函数API获取系统当前时间
  • 使用C代码中嵌入汇编代码触发系统调用获取系统当前时间
    • 传递了一个系统调用号 - eax
    • 传递了参数 - ebx

给MenuOS增加time和time-asm命令

  • 更新menu代码到最新版
  • 在main函数中增加MenuConfig(一个命令一行,与上面的格式一样)
  • 增加对应的time和time-asm函数(就是上周写的两个函数)
  • make rootfs (rootfs是一个脚本,可以自动生成,编译)

使用gdb跟踪系统调用内核函数sys_time

  • c:继续执行,停在断点处
  • n/s:单步运行,s进入函数,n不进入

系统调用在内核代码中的处理过程

  • int 0x80触发一个系统调用 ->执行系统调用处理函数system_call ->返回到用户态

    • 返回到用户态之前有一个进程调度的时机,会跟踪到schedule
  • 中断向量:int 0x80 ->system_call,初始化时绑定
  • 系统调用号:将xyz和中断服务程序sys_xyz关联起来
  • 系统调用机制的初始化
    • main.c中start_kernel函数:trap_init()

      • set_system_trap_gate(SYSCALL_VECTOR,&system_call)
      • SYSCALL_VECTOR:系统调用的中断向量
      • &system_call:汇编代码入口
  • 理解system_call到iret之间的主要代码
    • 从系统调用入口开始:ENTRY(system_call)
    • SAVE_ALL //保存现场
    • system_call中:call *system_ call_table(,%eax,4) //调用了系统调用处理函数,有系统调用号eax中,是实际的系统调用处理程序。
    • 当前任务syscall_ exit_ work里面有work_ pending里面有work_ notifysig //处理pending信号,不用管
    • 重要的是work_ resched:call schedule //决定了进程调度的代码,调用完会跳转到restore_all
    • restore_all //恢复现场
    • INTERRUPT_ RETURN //irp_return宏,中断处理过程在这结束

五、进程的描述和进程的创建

进程的描述

  • 操作系统的三大管理功能:

    • 进程管理(最重要的)
    • 内存管理
    • 文件系统
  • 进程控制块PCB task_struct:
    • 进程状态
    • 进程打开的文件
    • 进程优先级信息
  • 进程描述符task_struct数据结构

进程的创建

  • 进程的创建概览

    • 道生一(start_ kernel....cpu_idle)
    • 一生二(kernel_init和kthreadd)
    • 二生三(即前面0、1和2三个进程)
    • 三生万物(1号进程是所有用户态进程的祖先,2号进程是所有内核线程的祖先)
  • fork创建一个子进程
    • fork在父进程和子进程各返回一次
  • 创建一个新进程在内核中的执行过程
  • 新进程从哪里开始执行?
    • fork出来的子进程是从ret_from_fork开始执行的,然后跳转到syscall_exit,从系统调用中返回。

六、可执行程序的装载

预处理、编译、链接和目标文件的格式

  • 可执行程序是怎么得来的?

    • C代码
    • 编译器预处理
    • 编译成汇编代码
    • 汇编器编译成目标代码
    • 链接成可执行文件
    • 操作系统加载到内存执行
  • 目标文件的格式ELF
  • 静态链接的ELF可执行文件和进程的地址空间
    • 默认加载起始地址是0x8048000
    • ELF头部大小不同,程序入口点也将不同,程序入口在头部有定义:Entry point address,即是可执行文件加载到内存中开始执行的第一行代码

可执行程序、共享库和动态链接

  • 装载可执行程序之前的工作

    • 可执行程序的执行环境
    • 命令行参数和环境变量是如何保存和传递的?
    • 参数传递过程:shell程序 -> execve系统调用 -> sys_execve 内核处理函数在初始化新程序堆栈时拷贝进去
  • 装载时动态链接和运行时动态链接应用举例
    • 准备.so文件
    • 分别以共享库和动态加载共享库的方式使用libshlibexample.so文件和libdllibexample.so文件

可执行程序的装载

  • 可执行程序的装载相关关键问题分析

    • 特殊系统调用:fork、execve
    • sys_execve内部会解析可执行文件格式
    • execve系统调用返回到用户态从哪里开始执行?load_ elf_ binary -> start_thread
  • sys_execve的内部处理过程
  • 使用gdb跟踪sys_execve内核函数的处理过程
  • 可执行程序的装载与庄生梦蝶的故事
  • 浅析动态链接的可执行程序的装载

七、进程的切换和系统的一般执行过程

进程切换的关键代码switch_to分析

  • 进程调度与进程调度的时机分析

    • 中断处理过程(包括时钟中断、I/O中断、系统调用和异常)中,直接调用schedule(),或者返回用户态时根据need_resched标记调用schedule();
    • 内核线程(只有内核态没有用户态的特殊进程)可以直接调用schedule()进行进程切换,也可以在中断处理过程中进行调度,也就是说内核线程作为一类的特殊的进程可以主动调度,也可以被动调度;
    • 用户态进程无法实现主动调度,只能被动调度,仅能通过陷入内核态后的某个时机点进行调度,即在中断处理过程中进行调度。
  • 进程上下文切换相关代码分析
    • 为了控制进程的执行,内核必须有能力挂起正在CPU上执行的进程,并恢复以前挂起的某个进程的执行,这叫做进程切换、任务切换、上下文切换;
    • 挂起正在CPU上执行的进程,与中断时保存现场是不同的,中断前后是在同一个进程上下文中,只是由用户态转向内核态执行;
    • 进程上下文包含了进程执行需要的所有信息
      • 用户地址空间:包括程序代码,数据,用户堆栈等
      • 控制信息:进程描述符,内核堆栈等
      • 硬件上下文(注意中断也要保存硬件上下文只是保存的方法不同)
    • schedule()函数选择一个新的进程来运行,并调用context_switch进行上下文的切换,这个宏调用switch_to来进行关键上下文切换
      • next = pick_ next_task(rq, prev);//进程调度算法都封装这个函数内部
      • context_switch(rq, prev, next);//进程上下文切换
      • switch_to利用了prev和next两个参数:prev指向当前进程,next指向被调度的进程

Linux系统的一般执行过程

  • Linux系统的一般执行过程分析

    • 中断上下文的切换(中断和中断返回时CPU进行上下文切换)
    • 进程上下文的切换(进程调度过程中,从一个进程的内核堆栈切换到另一个进程的内核堆栈)
  • Linux系统执行过程中的几个特殊情况
    • 通过中断处理过程中的调度时机,用户态进程与内核线程之间互相切换和内核线程之间互相切换,与最一般的情况非常类似,只是内核线程运行过程中发生中断没有进程用户态和内核态的转换;
    • 内核线程主动调用schedule(),只有进程上下文的切换,没有发生中断上下文的切换,与最一般的情况略简略;//用户态进程不能主动调用
    • fork:创建子进程的系统调用在子进程中的执行起点(next_ ip = ret_ from_ fork)返回用户态,进程返回不是从标号1开始执行,直接跳转到ret_ from_fork执行然后返回到用户态;
    • 加载一个新的可执行程序后返回到用户态的情况,如execve,只是中断上下文在execve系统调用内部被修改了;

Linux系统架构和执行过程概览

  • Linux操作系统架构概览
  • 最简单也是最复杂的操作--执行ls命令
  • 从CPU和内存的角度看Linux系统的执行

学习心得

收获

还记得第一次看视频的时候是寒假,那时还在家,转眼我已经跟着网络课程学习了两个月,每周固定的看视频、做笔记、写博客、做实验,到现在已经有点习惯这种生活,突然没有视频可学,还有点空虚呢。依稀记得第一次视频老师您还说是除夕,听得到外面的鞭炮声,想想老师也是很辛苦的,很感谢老师能教给我们这么多知识。第一次亲身经历这种学习方式,也体验到了很多好处,比如每周的自评和互评,可以看到很多优秀的博客,加以学习,让自己变得更好,看见差的博客,会指出他的问题,也希望可以帮助到其他人。

通过八周的学习,第一次系统全面的理解了Linux系统:

  • 首先是进程的创建,由0号进程idle创建其子进程1号进程init和2号进程kthreadd,1号进程是所有用户态进程的祖先,2号进程是所有内核线程的祖先。由fork来创建一个新的子进程
  • 系统调用其实就是一种中断,从用户态转到内核态,发生中断时关键点是中断上下文的切换(中断和中断返回时CPU进行上下文切换)。
  • 由中断返回到用户态之前有一个进程调度时机,可能就会发生进程切换,关键点是进程上下文的切换(进程调度过程中,从一个进程的内核堆栈切换到另一个进程的内核堆栈),调用了schedule(),关键切换由switch_to执行。
  • 进程是依附于程序存在的,可执行程序是通过预编译、编译、汇编、链接生成的。由execve装载一个可执行程序。

遗憾

虽然每周都在按部就班的学习,但还是在一些具体的问题上不求甚解,是一直跟着老师的思路在走,老师讲过的就知道,自己去看其他的就蒙圈了,没有更深的去理解,有一些游走于表面,特别是对代码啊堆栈的理解就有些模糊。还有就是总觉得老师的逻辑跟我的有点不太一样,每次跟着听都有些费劲,感觉太散了,自己要看几遍才能理解,然后总结按自己的想法去串一遍,自认效率比较低,所以花的时间就很多。

20135220谈愈敏Linux_总结的更多相关文章

  1. 20135220谈愈敏Blog8_进程的切换和系统的一般执行过程

    进程的切换和系统的一般执行过程 谈愈敏 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-100002 ...

  2. 20135220谈愈敏Blog7_可执行程序的装载

    可执行程序的装载 谈愈敏 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1000029000 一. ...

  3. 20135220谈愈敏Blog6_进程的描述和创建

    进程的描述和创建 谈愈敏 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1000029000 进程 ...

  4. 20135220谈愈敏Blog2_操作系统是如何工作的

    操作系统是如何工作的 谈愈敏 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 计 ...

  5. 20135220谈愈敏Blog3_构造一个简单的Linux系统MenuOS

    构造一个简单的Linux系统MenuOS 谈愈敏 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1 ...

  6. 20135220谈愈敏Blog4_系统调用(上)

    系统调用(上) 谈愈敏 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1000029000 用户态 ...

  7. 20135220谈愈敏Blog5_系统调用(下)

    系统调用(下) 谈愈敏 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1000029000 给Me ...

  8. 20135220谈愈敏Linux Book_17

    第17章 设备与模块 关于设备驱动和设备管理的四种内核成分: 设备类型:在所有 Unix 系统中为了统一普通设备的操作所采用的分类. 模块: Linux 内核中用于按需加载和卸载目标码的机制. 内核对 ...

  9. 20135220谈愈敏Linux Book_4

    进程调度 进程:程序的运行态表现形式 进程调度程序:确保进程能有效工作的一个内核子系统,决定将哪个进程投入运行.何时运行以及运行多长时间,在可运行态进程之间分配有限的处理器时间资源. 最大限度的利用处 ...

随机推荐

  1. 在阿里云主机的Debian操作系统上安装Docker

    因为需要新搭建饭团网站,所以需要在阿里云的主机上跑数据库,java环境. 考虑到可扩展性和模块化,所以准备最近流行的docker技术.Docker -- 从入门到实践 阿里云主机1核1G,资源不多,所 ...

  2. 数据库相关 sql 语句

    1.操作某数据库 use 数据库名称,然后可以操作该数据库下的某张表 2.$res=mysql_query($sql); 该语句如果用在封装的函数体里,则不用传入第二个参数$conn来指定连接,这样才 ...

  3. 【mysql】关于Index Condition Pushdown特性

    ICP简介 Index Condition Pushdown (ICP) is an optimization for the case where MySQL retrieves rows from ...

  4. poj 2342 Anniversary party 简单树形dp

    Anniversary party Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 3862   Accepted: 2171 ...

  5. C# url信息获取

    假设当前页完整地址是:http://www.360jht.com/game/bbb.aspx?id=5&name=kelli "http://"是协议名 "www ...

  6. web.xml文件报错:cvc-complex-type.2.4.a: Invalid content was found starting with element 'init-param'.

    <?xml version="1.0" encoding="UTF-8"?> <web-app version="3.0" ...

  7. Oracle Stored Procedure demo

    1.how to find invalid status stored procedure and recompile them? SELECT OBJECT_NAME , status FROM u ...

  8. 我的NopCommerce之旅(6): 应用启动

    一.基础介绍 Global.asax 文件(也称为 ASP.NET 应用程序文件)是一个可选文件,该文件包含响应 ASP.NET 或 HTTP 模块所引发的应用程序级别和会话级别事件的代码. Appl ...

  9. [转]GridView排序——微软提供Sort

    本文转自:http://www.cnblogs.com/eva_2010/articles/1995646.html 在GridView中,根据其中的某列进行排序. 1. 页面:AllowSortin ...

  10. hadoop入门:hadoop使用shell命令总结

    第一部分:Hadoop Bin后面根据项目的实际需要Hadoop Bin  包括:Hadoop  hadoop的Shellhadoop-config.sh 它的作用是对一些变量进行赋值     HAD ...