Linux系统理解以及Linux系统学习心得

原创作品转载请注明出处  《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

作者:严哲璟

说一下我对Linux系统的理解

1.加载Linux内核准备:在加载基本输入输出模块(BIOS)之后,从磁盘的引导扇区读入操作系统的代码文件块到内存中,之后开始整个系统的初始化.

2.main.c的start_kernel函数是整个操作系统的入口,这也与Linux是基于C语言的特性相符,start_kernel具体做的动作很多,包括死锁检测,指定多核CPU的ID,栈溢出保护,关闭中断,初始化内存页,以及一些重要模块,如mm_struct,trap_init,schedule_init,以及set(init_task)强制性手动创建一个0号进程即IDLE进程,当只有一个进程的时候,不断循环.

3.rest_init创建一个新的进程(用户进程),pid=1,进程的启动需要 sche_init模块

这些是操作系统最基本的核心,然后我们还有其他的功能,如进程管理,内存管理,文件管理.其中最重要当属进程管理.

进程管理最核心的是进程的切换和中断机制,中断有很多种,如软中断,即系统调用,陷阱,系统异常等等,还有硬中断,如IO中断

中断方式上面硬中断是通过相关的硬件中断处理器,如我们点击键盘触发相关的硬件中断,处理器进入相关的中断状态,在此略去.

而软中断主要是通过相应的系统指令(主要是int)指令去触发,软中断可以是程序本身的行为(系统调用),也可能是CPU为了保护计算机而做出的一种反应(异常).

系统调用主要分为3层:第一是相关的API,即应用程序接口,如read(),write(),getpid()等等,第二层是这些高级接口对应的中断向量表中的偏移,即syscall_table中的序号,对应一个中断服务程序.第三层是system_call保存当前上下文进入中断服务程序进行处理.处理完成之后iret,返回用户程序,在这之前,(应该说从内核态转为用户态的时候)检查进程调度标识,是否需要调度.

进程的创建和切换:通过系统调用fork(),创建一个与父进程完全一样的子进程,包括代码段完全一样,但是子进程的返回值为零,而且子进程的返回用户态的堆栈地址被改变了,其实这也很好理解,你一个子进程要做其他的事情,需要自己的用户空间和内核空间.不仅如此,当父进程执行了,子进程被调度执行的时候,子进程开始执行的地方是ret_from_fork,其下一句就是iret,而通过稍微修改在子进程的内核堆栈中保存的那些数据,iret就可以还原一个与父进程稍微不一样的子进程了.

进程的切换:关键函数是shcedule()和switch_to(),根据不同的进程优先级算法,如LRU,CLOCK,FIFO等,在就绪(3状态为就绪,阻塞,运行)的进程队列里挑选一个出来执行,这其中的关键部分是schedule(),当检测到一个进程需要调度的时候,从用户态切换到内核态执行内核代码(3G以上的区域),维护一个结构,此结构中保存当前被调度准备执行的进程在上一次被调度出去就绪或阻塞的时候执行的下一句代码,并且保存进程的用户堆栈,由于此代码是内核代码,对所有进程可见并通用,因此执行到此处都是一样的.通过switch_to,进程得以回复原来的用户堆栈的sp,以及eip,得以继续执行.之后schedule()返回,重新回到用户态,但是eip和esp都与上一个进程不一样了.

进程加载可执行文件:假设我们在运行shell进程,要执行cd /home这个命令,我们需要加载cd这个可执行文件,在linux上面,终端命令基本都被作为可执行文件,保存在/usr/bin中,在执行的时候,需要加载,并且传入一定参数.首先我们fork出一个新进程,但是在fork的新子进程中,我们需要调用exec类函数来加载一个可执行文件.加载这个可执行文件的具体过程是:调用启动加载器,加载器删除子进程现有的虚拟存储器段(后面会说)并创建一组新的代码,数据,堆,和栈,新的栈和堆被初始化为零,通过将虚拟地址空间中的页映射到可执行文件的页,新的代码和数据段被初始化为可执行文件的内容.最后加载器跳转到_start地址,最终从可执行目标文件中调用相应的main()函数,因此子进程就变成一个新的进程,其功能是可执行目标文件的功能,如上述所说,打开/home这个目录,将当前目录置为/home.C语言的编译和链接分为静态和动态链接,其中静态链接是将所有的头文件一起编译链接,动态链接分为共享库动态链接和运行时动态链接.共享库是/usr/lib中的一些动态链接库,其作用是只在加载的时候链接而不需要重新编译,这样链接非常方便,修改也可以独立修改.而运行时动态链接需要加载加载器,其本身也是一个共享库.

下面是个人理解的Linux32位的进程映像(即课件说的进程地址空间,是虚拟存储器)



内核虚拟存储器3G以上



用户栈(运行时创建),下面的这条线代表ESP,栈往下增长




共享库的存储器区域




运行时堆(malloc)往上增长



读写段,或者叫数据段,在可重定位目标文件中是data和bss字段



只读段或者是代码段(与上面的段都是从obj可执行文件中加载,下面的线是0x08048000)



总结部分:我对这门课的评价非常高,这门课让我对计算机的系统原理和系统实现有了非常好的认识,孟宁老师先从linux32位机器码说起,阐述了程序的机器级代码的实现,以及一些ASM的C汇编,让我们对机器代码有了一个比较好的认识,其次,老师讲述了进程,程序的映像以及在栈中程序的行为,之后老师再讲到进程的切换以及中断,最后课程讲授链接和加载的过程,让我们学会制作一些简单的共享库,理解了大型程序是怎么构造,以及理解其他重要的系统概念.

学完这门课之后,最大的收获是初步认识了操作系统的本质,以及当我们机器出现问题了,应该找到什么样的问题去尝试解决.

最大的遗憾是,由于时间实在太少,没能非常仔细的把全部内容熟悉,可能还有一些地方有疏漏



Linux系统理解以及Linux系统学习心得

时间: 2024-08-01 10:43:48

Linux系统理解以及Linux系统学习心得的相关文章

Android学习心得(16) --- Dex文件结构实例解析(2)

我在博客上发表一些我的Android学习心得,希望对大家能有帮助. 这一篇我们讲述一下通过一个实例来分析dex文件结构和组成. 参考Leb128数据类型 Android学习心得(5) --- dex数据类型LEB128 参考实例分析学习理解dex文件结构Android学习心得(15) --- Dex文件结构解析(1) 参考baksmali工具使用Android学习心得(4) --- MAC下smali文件编写与运行 1.编译 我们通过一个例子来分析dex文件的构成 创建一个Hello.java文

Android学习心得(15) --- Dex文件结构解析(1)

我在博客上发表一些我的Android学习心得,希望对大家能有帮助. 这一篇我们讲述一下Android可执行文件dex的结构解析. 参考Leb128数据类型 Android学习心得(5) --- dex数据类型LEB128 参考实例分析学习理解dex文件结构Android学习心得(15) --- Dex文件结构解析(1) 1.Dex背景 Android应用开发和Dalvik虚拟机Android应用所使用的编程语言是Java语言,在编译时使用JDK将Java源程序编程成标准的Java字节码文件. 而

一点点linux系统的学习心得

我相信你正在阅读本文的时候,可能是因为你渴望学习Linux技术.我想分享一下过去两年中我自己的一些学习经历,希望你能更顺利地成为Linuxer. 两年前在Linux系统的运行和维护方面找到了一份工作(当时估计该公司非常缺乏,哈哈),我在收到录取通知后才开始学习Linux技术.但是,由于本科生不是计算机专业,我甚至不知道CPU,内存,硬盘等的概念,我也不知道他们的功能到底是什么.坦率地说,我的Linux知识,包括计算机基础,都是在下班后学到的.所以,如果你对计算机有一定的了解,请相信Linux对你

LINUX内核分析第八周学习总结——进程的切换和系统的一般执行过程

LINUX内核分析第八周学习总结——进程的切换和系统的一般执行过程 黄韧(原创作品转载请注明出处) <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.知识概要 Linux中进程调度的基本概念与相关知识 schedule函数如何实现进程调度 Linux进程的执行过程(一般情况与特殊情况) 宏观描述Linux系统执行 二.学习笔记 (一)进程切换的关键代码switch_to分析 进程进度与进程调度的时机分析 1.

linux基础学习-03-操作系统发展历程及系统版本选择

第1章 Linux简介 1.1 什么是操作系统? 简单讲:操作系统就是一个人与计算机硬件的中介. 操作系统,英文名称Operating System,简称OS,是计算机系统中必不可少的基础系统软件,它是应用程序运行以及用户操作必备的基础环境支撑,是计算机系统的核心. 操作系统的作用是管理和控制计算机系统中的硬件和软件资源,例如,它负责直接管理计算机系统的各种硬件资源,如对CPU,内存,磁盘等的管理,同时对系统资源供需的优先次序进行管理.操作系统还可以控制设备的输入,输出以及操作网络与管理文件系统

Linux运维系统工程师与java基础学习系列-8

Java天生骄傲系列-8 函数的应用(重点掌握) 如何定义函数 例1: package test.myeclipse;                 publicclass test1 { publicstaticvoid main(String[]args) { int Sum = getSum(); System.out.println("Sum="+Sum); } publicstaticint getSum() { return 3+4; } } 运行结果:Sum=7 例2:

Linux运维系统工程师与java基础学习系列-4

Java天生骄傲系列-4 程序流程控制 判断 选择 循环 判断结构: If语句三种格式: 1.  if(条件表达式) { 执行语句: } 2.  if(条件表达式) { 执行语句: } else { 执行语句: } 3.  if(条件表达式) { 执行语句: } else if (条件表达式) { 执行语句: } --. else { 执行语句: } if(条件表达式) { 执行语句: } 牛刀小试: package test.myeclipse; publicclass test1 { pub

LINUX内核分析第三周学习总结——构造一个简单的Linux系统MenuOS

LINUX内核分析第三周学习总结——构造一个简单的Linux系统MenuOS 黄韧(原创作品转载请注明出处) <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 回顾: [计算机三个法宝] 1)存储程序计算机 2)函数调用堆栈 3)中断 [操作系统两把宝剑] 1)中断上下文的切换:保存现场和恢复现场 2)进程上下文的切换 一.使用gdb跟踪调试内核从start_kernel到init进程启动 使用实验楼的虚拟机打开

Linux运维系统工程师与java基础学习系列-2

Java天生骄傲系列-2 运算符 1.   算术运算符 注: 1)"+"号除了用于加法运算以外,还用作字符串连接符: 2)字符串数据和任何数据使用+都是相连接,最终都会变成字符串. package day4javatest.myeclipse;         publicclass day4test1 { /** * @param args */ publicstaticvoid main(String[]args) { // TODO Auto-generated method s