zoukankan      html  css  js  c++  java
  • Linux内核分析期中总结

    Linux内核分析期中总结

    跟踪分析Linux内核的启动过程

    过程分析:

    在Linux内核的启动过程中,一共经历了start_kernel,rest_init,kernel_thread等几个函数的执行。其中start_kernel相当于普通C程序的main函数。Trap_init负责初始化中断向量,

    mm_init负责内存管理模块初始化,sche_init负责调度模块初始化。

    两把宝剑:

    1.中断上下文切换

    2.进程上下文切换

    三大法宝:

    1.存储程序计算机

    2.函数调用堆栈

    3.中断

    0号进程

    有一个全局变量init_task,是手工创建的PCB,也是最后的idle进程,与rest_init函数有配合作用。

    计算机的启动过程概述

    1. x86 CPU启动的第一个动作CS:EIP=FFFF:0000H(换算为物理地址为000FFFF0H,因为16位CPU有20根地址线),即BIOS程序的位置。

    2.BIOS例行程序检测完硬件并完成相应的初始化之后就会寻找可引导介质,找到后把引导程序加载到指定内存区域后,就把控制权交给了引导程序。这里一般是把硬盘的第一个扇区MBR和活动

    分区的引导程序加载到内存(即加载BootLoader),加载完整后把控制权交给BootLoader。

    3.引导程序BootLoader开始负责操作系统初始化,然后起动操作系统。启动操作系统时一般会指定kernel、initrd和root所在的分区和目录,比如root (hd0,0),kernel (hd0,0)/bzImage

    root=/dev/ram init=/bin/ash,initrd (hd0,0)/myinitrd4M.img

    4.内核启动过程包括start_kernel之前和之后,之前全部是做初始化的汇编指令,之后开始C代码的操作系统初始化,最后执行第一个用户态进程init

    5.一般分两阶段启动,先是利用initrd的内存文件系统,然后切换到硬盘文件系统继续启动。

    initrd文件的功能主要有两个:

    1、提供开机必需的但kernel文件(即vmlinuz)没有提供的驱动模块(modules)

    2、负责加载硬盘上的根文件系统并执行其中的/sbin/init程序进而将开机过程持续下去

    编译内核

    1.原因:生成符号表

    2.方法:

    (1)make config操作简单,耗时

    (2)make menuconfig图形化界面

    (3)make allnoconfig 全no选择处理

    系统调用的工作机制

    内核态

    执行级别高,可以执行特权指令,访问任意物理地址,在intel X86 CPU的权限分级为0级。

    用户态

    执行级别低,只能访问0x00000000-0xbfffffff之间的逻辑地址,权限分级为3级。

    区分与切换

    CS:eip(代码段选择寄存器/偏移量寄存器)中,CS寄存器最低两位表示特权级。状态通过中断来切换,包括硬件中断和系统调用两种方式。

    寄存器上下文

    从用户态切换到内核态时,int指令会保存用户态的寄存器上下文到内核堆栈中,同时会把当前内核态的一些信息加载,例如cs:eip指向中断处理程序入口。

    • 用户态栈顶地址

    • 当时状态字

    • 当时cs:eip

    系统调用三层皮(以API xyz为例)

    • API xyz

    • 中断向量system_call

    • 中断服务程序sys_xyz

    系统调用号通过eax寄存器传递,将API xyz和中断服务程序sys_xyz关联起来。

    分析Linux内核创建一个新进程的过程

    进程的两种虚拟机制:虚拟处理器,虚拟内存

    任务队列:链表每一项都是进程描述符结构。

    进程描述符描述内容:打开的文件,进程地址空间,挂起信号,进程状态

    进程状态:

    进程描述符中state域描述了进程的当前状态。

    TASK_RUNNING(可执行)

    TASK_INTERRUPTIBLE(正被阻塞)

    TASK_UNINTERRUPTIBLE(不可中断)

    _TASK_TRACED(被其他进程跟踪)

    _TASK_STOPPED(进程停止执行)

    进程家族

    所有进程都是PID为1的init进程的后代,内核在系统启动的最后阶段启动init进程

    进程创建

    1 fork()通过拷贝当前进程创建一个子进程
    2 exec()函数读取可执行文件并将其载入地址空间

    线程实现

    在linux中,线程仅仅被视作一个与其他进程共享某些资源的进程,它只是一种进程间共享资源的手段

    内核线程:

    独立运行在内核空间中的标准进程

    它与普通进程的区别在于,内科线程没有独立的地址空间,只在内核空间运行。可以被调度或者抢占。

    由源代码生成可执行文件

    预处理 => 编译 => 汇编 => 链接

    gcc -E hello.c -o hello.i
    gcc –S hello.i –o hello.s
    gcc –c hello.s –o hello.o
    gcc hello.o –o hello
    

    若无-o指明,生成可执行文件默认为a.out

    目标文件格式

    目标文件分为PE(windows)和ELF(linux)。

    查看ELF文件头部方法:readelf

    静态链接ELF可执行文件默认入口点:0x8048000

    动态链接执行方法:

    $ gcc main.c -o main -L/path/to/your/dir -lshlibexample -ldl -m32
    $ export LD_LIBRARY_PATH=$PWD 
    /*将当前目录加入默认路径,否则main找不到依赖的库文件,当然也可以将库文件copy到默认路径下。*/
    

    -L + 路径 或者 -l + 库名

    静态链接和动态链接的区别

    静态连接:elf_entry指向可执行文件头部,是新程序执行的起点

    动态链接:elf_entry指向ld(动态链接器)的起点,加载load_elf_interp

    进程调度的时机

    直接调用:中断处理过程(包括时钟中断,I/O中断,系统调用和异常)

    返回用户态时调用:根据need_resched标记调用

    内核线程可以主动调用也可以被动调用

    用户态线程仅能在陷入内核态后,即在中断处理过程中调度

    进程上下文

    用户地址空间:代码,数据,堆栈等

    控制信息:进程描述符,内核堆栈

    硬件上下文

    pick_next_task(rq,prev);进程调度算法封装

    context_switch(rq,prec,next);进程上下文切换

    switch_to中prev指向当前进程,next指向被调度进程

    总结:

    通过半个学期对Linux内核的学习,我对上个学期接触过的操作系统的运行机制有了进一步的了解,同时也对C语言进行底层的系统操作有了初步认识,这可以加深我对于软件工程一些思想的

    理解,同时也可以提高我的系统级C语言编程操作的水平。

  • 相关阅读:
    单例模式 2中创建方法
    Interger 与 int
    java equals 和 "==" 比较
    java 小知识点
    对象复制、克隆、深度clone
    onsubmit="return false;"报错
    js 在myeclipse中报错
    struts2 标签 --<<s:url >
    struts2 标签问题----日期显示
    mysql 建表语句
  • 原文地址:https://www.cnblogs.com/20135319zl/p/5414574.html
Copyright © 2011-2022 走看看