计算机系统大作业


   计算机系统 大作业  题     目  程序人生-Hello’s P2P  专       业 计算机科学与技术        学     号  1180300403             班     级  1803004                学       生  王心雷                指 导 教 师   史先俊                       计算机科学与技术学院2019年12月摘  要Hello.c,一个看起来很简单的c文件,但其背后却蕴含着复杂的生命历程。它经过预处理,编译,汇编,链接,一步步的来到这个世上。他执行的结果是简单的,但其中间的道路是坎坷的。它的出生也要靠母亲的力量-计算机系统,计算机对他进行了无微不至的照顾,为他分配进程,分配空间,让cache与内存与磁盘和他进行密切的配合,生怕他哪一步出现了错误,即使出现错误也会调用专用的异常处理程序,对他进行检查。就连他的结束,计算机系统也要照顾到。就是这样的一个个hello让程序可与现实世界连通。 关键词:预处理,编译,进程,存储,IO,链接;                                    
目  录 第1章 概述 - 4 -1.1 Hello简介 - 4 -1.2 环境与工具 - 4 -1.3 中间结果 - 4 -1.4 本章小结 - 4 -第2章 预处理 - 5 -2.1 预处理的概念与作用 - 5 -2.2在Ubuntu下预处理的命令 - 5 -2.3 Hello的预处理结果解析 - 5 -2.4 本章小结 - 5 -第3章 编译 - 6 -3.1 编译的概念与作用 - 6 -3.2 在Ubuntu下编译的命令 - 6 -3.3 Hello的编译结果解析 - 6 -3.4 本章小结 - 6 -第4章 汇编 - 7 -4.1 汇编的概念与作用 - 7 -4.2 在Ubuntu下汇编的命令 - 7 -4.3 可重定位目标elf格式 - 7 -4.4 Hello.o的结果解析 - 7 -4.5 本章小结 - 7 -第5章 链接 - 8 -5.1 链接的概念与作用 - 8 -5.2 在Ubuntu下链接的命令 - 8 -5.3 可执行目标文件hello的格式 - 8 -5.4 hello的虚拟地址空间 - 8 -5.5 链接的重定位过程分析 - 8 -5.6 hello的执行流程 - 8 -5.7 Hello的动态链接分析 - 8 -5.8 本章小结 - 9 -第6章 hello进程管理 - 10 -6.1 进程的概念与作用 - 10 -6.2 简述壳Shell-bash的作用与处理流程 - 10 -6.3 Hello的fork进程创建过程 - 10 -6.4 Hello的execve过程 - 10 -6.5 Hello的进程执行 - 10 -6.6 hello的异常与信号处理 - 10 -6.7本章小结 - 10 -第7章 hello的存储管理 - 11 -7.1 hello的存储器地址空间 - 11 -7.2 Intel逻辑地址到线性地址的变换-段式管理 - 11 -7.3 Hello的线性地址到物理地址的变换-页式管理 - 11 -7.4 TLB与四级页表支持下的VA到PA的变换 - 11 -7.5 三级Cache支持下的物理内存访问 - 11 -7.6 hello进程fork时的内存映射 - 11 -7.7 hello进程execve时的内存映射 - 11 -7.8 缺页故障与缺页中断处理 - 11 -7.9动态存储分配管理 - 11 -7.10本章小结 - 12 -第8章 hello的IO管理 - 13 -8.1 Linux的IO设备管理方法 - 13 -8.2 简述Unix IO接口及其函数 - 13 -8.3 printf的实现分析 - 13 -8.4 getchar的实现分析 - 13 -8.5本章小结 - 13 -结论 - 14 -附件 - 15 -参考文献 - 16 -  
第1章 概述1.1 Hello简介P2P1. 预处理将hello.c 所引用的头文件stdio.h,unistd.h和stdlib.h中的内容直接插入程序文本中,得到另一个c程序名为hello.i2. 编译编译器将汇编文件hello.i翻译成内含汇编语言的文件hello.s,它包含一个汇编程序文件。3.汇编 汇编器(as)将hello.s翻译成机器语言指令,把这些指令打包成一种叫做“可重定位目标程序”的格式,并将结果保存在hello.o中。hello.o文件是一个二进制文件,它包含的17个字节是函数main的指令编码。3. 链接阶段链接器将hello.o与C标准库或者其他文件合并,生成可执行文件hello,此时在控制台输入./hello即可直接运行。  020Shell 调用 execve ,找出虚拟内存页并映射,进入程序入口后程序载入物理内存,然后执行目标代码,CPU为其分配时间片。程序运行结束后,shell父进程回收hello进程,内核删除相关数据结构。  1.2 环境与工具1.2.1 硬件环境1.104GB固态硬盘,800GB机械硬盘处理器:Intel® Core™ i7-7500U CPU @ 2.70GHz 2.90GHz1.2.2 软件环境1.windows10 操作系统2.ubuntu操作系统3.directX11等环境1.2.3 开发工具Gcc编译器,GDB编译器,codeblocks,VS2017等   1.3 中间结果Hello.i:预处理后的文件Hello.s:汇编文件Hello.o:可重定位目标文件Hello:可执行文件Hello.elf: 可重定位目标文件elf 1.4 本章小结本章为总领章节,为下面的讲述理清脉络。   
第2章 预处理2.1 预处理的概念与作用预处理主要由预处理器完成。这一阶段一共完成4件事。1)头文件的展开:将程序中所用的头文件用其内容来替换头文件名。2)宏替换:扫描程序中的符号,将其 替换成宏所定义的内容。3)去掉注释:去掉程序中的注释。4)条件编译:在程序中难免会有文件的重复引用,如果每次引用都要重新调用文件中的内容,这样就会增加许多不必要的开销 。所以为了防止这种情况的发生,我们在文件中使用条件编译符号来防止这种情况的发生。2.2在Ubuntu下预处理的命令下面第一张图为ubuntu下的预处理命令 ubuntu下的预处理命令下面几张图为ubuntu下的预处理命令     ubuntu下的预处理命令  2.3 Hello的预处理结果解析输入预处理命令后,gcc处理hello.c后生成文件hello.i. Hello.i是hello.c将头文件中的数据插入文件的产物,因此较大。Gcc将hello.中所有的宏定义翻译成为#ifdef与#endef,。hello.c的程序文段在插入的头文件代码段之后。 预处理文件2.4 本章小结 预处理总结一下就是替换与展开。将引用的头文件中的代码插入文件后,用#ifdef与#endef替换全局宏定义#define。本章主要介绍了预处理的定义与作用、并结合预处理之后的程序对预处理结果进行了解析。 (第2章0.5分)
第3章 编译3.1 编译的概念与作用简单来讲,编译就是通过编译器,将已经预处理过的.i文件变异成汇编文件.s。其中, 汇编文件的内容即为和.i文件中语句对应的汇编代码。汇编语句是非常有用的,因为它为为不同的编译器和不同的高级语言都设置了相同的输出语言。编译的过程分为分析和综合两部分,并进一步划分为词法分析、语法分析、语义分析、目标文件的生成等等。词法分析:识别单词(即标识符、常数、保留字,以及各种运算符、标点符号等)、造符号表和常数表,以及将源程序换码为编译程序易于分析和加工的内部形式语法分析:根据语言的语法规则,检查源程序是否合乎语法。如不合乎语法,则输出语法出错信息;如合乎语法,则分解源程序的语法结构,构造中间语言形式的内部程序目标文件生成:其主要工作包括代码优化、存储分配和代码生成。代码优化是通过重排和改变程序中的某些操作,以产生更加有效的目标程序。存储分配的任务是为程序和数据分配运行时的存储单元。代码生成的主要任务是产生与中间语言程序符等价的目标程序,顺序加工中间语言程序,并利用符号表和常数表中的信息生成一系列的汇编语言或机器语言指令。作用:将.i文件编译为.s文件,为汇编器提供汇编程序。 注意:这儿的编译是指从 .i 到 .s 即预处理后的文件到生成汇编语言程序3.2 在Ubuntu下编译的命令 编译命令3.3 Hello的编译结果解析Gcc将hello.c文件预处理后编译,得到汇编程序文件hello.s  数据结构字符串与字符数组程序中用到的字符串常量有两个,第一个为“用法 Hello 学号 姓名 秒数!\n”,第二个为“Hello %s %s\n”,其中两个字符串变量参数分别为argv 1,argv 2。两个字符串常量在汇编程序开头便已经声明。而字符串变量方面,main函数中有一个参数数组为字符串数组,char argv[],用于存储输入的字符串。   字符串地址 整型1. 循环变量ii是一个整型变量,在c程序中,i用于控制argc=4时进入的一个循环。而在汇编程序中,它被保存在%rbp-4这个地址空间中。  整型数据i 2. int argcargc如果不为4,那么输出字符串1后退出程序;如果为4,那么循环输出自己输入的姓名和学号。汇编程序中,它被保存在%rbp-20这一地址空间中。 整型数据argc3. 立即数汇编程序中出现的前面带有$符号的数字;被直接编入汇编程序中。赋值程序中涉及的赋值操作:1. int i=0,为循环变量赋初值。由于i为main函数中的局部变量, 一开始存出来寄存器edi中,被调用时存储在栈中的相应位置。 循环变量i的赋值 因为i为4个字节的整形数据,因此赋值时用的是movl.运算 汇编语言中,常见运算指令如下: ADD dst,srcdst<–dst+srcSUB dst,srcdst<–dst-srcADC dst,srcdst<–dst+src+CFSBB dst,srcdst<–dst-src-CFINC dstdst<–dst+1DEC dstdst<-dst-1NEG dstdst<–0-dstMUL srcAX<-AL8位src或  DX,AX<–AX 16位src   ;  IMUL srcAX<-AL8位src或 DX,AX<–AX 16位srcIDIV srcAX/8位src,AL<–商,AH<–余数 ; DX(高)、AX(低)/16位src,AX<–商,DX<–余数DIV srcAX/8位src,AL<–商,AH<–余数 ; DX(高)、AX(低)/16位src,AX<–商,DX<–余数  该程序中的运算为:1. 比较(if(argc!=4)),i<8将argc与4进行比较,如果不相等,返回0,输出字符串1结束;如果相等,返回1,进入L3控制的循环.将i与8比较,若i<8,则继续循环;若不是,跳出循环。2. 自增i++,每进行一次循环进行一次自增运算控制转移将argc与4进行比较,如果不相等,返回0,输出字符串1结束;如果相等,返回1,进入L3控制的循环.在汇编文件中,该控制转移用下面的代码实现 控制转移 还有一个即为上面多次提到的循环。初始化i为0,每进行一次循环i自增1,当i等于或大于8时跳出循环。 自增运算函数操作 函数方面,主要定义调用了以下几个:1. main函数参数传递:argv与argc分别用rdi与rsi存储函数调用:call @fuction函数返回:函数返回于累加器rax中,返回值为02. printf函数参数传递:第一个 printf 将%rdi 设置为“Usage: Hello 学号 姓名!\n”字符串的首地址。第二个 printf 设置%rdi 为“Hello %s %s\n”的首地址,设置%rsi 为 argv1,%rdx 为 argv2函数调用:call printf@PLT 3. exit 函数:参数传递:将%edi 设置为 1。函数调用:call exit@PLT。3. atoi函数: 参数传递:将%rdi设置为argv3 函数调用:call atoi@PLT4. sleep 函数:参数传递:将%edi 设置为 int(argv3)函数调用:call sleep@PLT。5.getchar 函数:函数调用:call gethcar@PLT3.4 本章小结编译过程中,c语言中的各条语句按照编译器的规则逐步翻译成汇编代码,存储在.s文件中。部分c语言的“简单操作”在汇编语言中可能需要多步运算和多种存储结构来实现。
第4章 汇编4.1 汇编的概念与作用把汇编语言翻译成机器语言的过程称为汇编汇编语言虽然已经非常接近机器语言的表达方式,但是计算机仍然无法直接读取。计算机能够直接读取的在,只有二进制的机器指令。因此,汇编就是将相较来说人类容易阅读的汇编代码翻译成机器能够读取的机器代码。例如,汇编将存储着汇编代码的hello.s文件转化成了hello.o,的可重定位目标文件。3.2 在Ubuntu下汇编的命令 汇编命令4.3 可重定位目标elf格式可重定位目标文件的elf格式如下: Elf格式 Elf头ELF头以一个16字节的序列开始,描述了生成该文件的系统的字的大小和字节顺序。ELF头剩下的部分包含帮助连接器语法分析和解释目标文件的信息。其中包括ELF头的大小、目标文件的类型(如可重定位、可执行、共享的)、机器类型(如x86-64)、节头部表的文件偏移,以及节头部表中条目的大小和数量。Elf头节头包含着以下各个节的类型、初始地址和偏移地址信息 节头    重定位节.rela.text ,一个.text 节中位置的列表,包含.text 节中需要进行重定位的信息,当链接器把这个目标文件和其他文件组合时,需要修改这些位置。.rela节中包含的信息有:Offset:需进行重定向的代码在.data与.text节中的偏移位置Info:包括symbol和type两部分,symbol 代表重定位到的目标在.symtab中的偏移量,type代表重定位的类型。Addend:计算重定位位置的辅助信息Type:重定位到的目标的类型Name:重定位的目标的名称。   重定位节.symtab主要包含符号表、过程和静态变量名、节名和位置。   符号表 下面以.L3 的重定位为例阐述之后的重定位过程:链接器根据 info 信息向.symtab 节中查询链接目标的符号,由 info.symbol=0x05,可以发现重定位目标链接到.rodata 的.L1,设重定位条目为 m,m的构造为:m.offset=0x18,m.symbol=.rodata, m.type=R_X86_64_PC32, m.addend=-4,重定位一个使用 32 位 PC 相对地址的引用。计算重定位目标地址的算法如下(设需要重定位的.text 节中的位置为 src,设重定位的目的位置 dst):<1>refptr = src +m.offset <2>refaddr = ADDR(src) +m.offset <3>refptr = (unsigned) (ADDR(m.symbol) + m.addend-refaddr)其中<1>指向 src 的指针<2>计算 src 的运行时地址,<3>中ADDR(m.symbol)计算 dst 的运行时地址,在本例中,ADDR(m.symbol获得的是 dst 的运行时地址,因为需要设置的是绝对地址,即 dst 与下一条指令之间的地址之差,所以需要加上 m.addend=-4。之后将 src 处设置为运行时值refptr,完成该处重定位。 3.3 Hello.o的结果解析机器语言本质上是一堆顺序特殊的二进制序列。每一条汇编语句都对应着一条机器指令。一些常见的Y86汇编语句与它们相对应的机器语言 反汇编的结果为   反汇编结果由图可知,push %rbp对应着一条十六进制的机器指令55,而mov是基本指令,诸如add,sub等指令都是由mov 加上对运算器的操作后复合而成的。操作指令后面的代码均为某个立即数,内存地址或某个寄存器。而机器语言中操作数与汇编语言不一致,是因为汇编语言在翻译成机器语言时,在.text(代码段)中去掉了一些代码,导致指令之间相对偏移量发生了改变,因此分支转移函数调用时,汇编代码与机器代码中偏移量不同。4.5 本章小结本章主要介绍了汇编过程,以及生成的可重定向目标文件的ELF结构,以及.o文件反汇编的代码与其机器代码的映射关系。重点讲解了目标符号在链接过程中的重定位过程。
第5章 链接5.1 链接的概念与作用链接是将各种代码和数据片段手机并组合成一个单一文件的过程。这个文件可被加载到内存并执行。链接可执行于编译时,可执行于加载时,亦可执行于运行时。在现代系统中,链接是由链接器来执行的。链接使得分离编译成为可能。5.2 在Ubuntu下链接的命令 Ubuntu下链接的命令5.3 可执行目标文件hello的格式 使用readelf -a hello > hello.elf命令得到hello 的elf文件   Hello的elf文件节头部分定义了各个段的偏移量,类型和地址。根据 Section Headers 中的信息我们就可以用 HexEdit 定位各个节所占的区间(起始位置,大小)。其中 Address是程序被载入到虚拟地址的起始地址    Hello节头     。5.4 hello的虚拟地址空间 Edb展示的虚拟地址空间    5.5 链接的重定位过程分析链接的重定位过程分析hello相对于hello.o有如下不同:1.hello相对hello.o多了很多的节。2.hello.o中的相对偏移地址到了hello中变成了虚拟内存地址3.hello中相对hello.o增加了许多的外部链接来的函数。4.hello.o中跳转以及函数调用的地址在hello中都被更换成了虚拟内存地址。 Hello.o的elf文件 Hello的elf文件 重定位:链接器在完成符号解析以后,就把代码中的每个符号引用和正好一个符号定义关联起来。此时,链接器就知道它的输入目标模块中的代码节和数据节的确切大小。然后就可以开始重定位步骤了,在这个步骤中,将合并输入模块,并为每个符号分配运行时的地址。在hello到hello.o中,首先是重定位节和符号定义,链接器将所有输入到hello中相同类型的节合并为同一类型的新的聚合节。然后,链接器将运行时内存地址赋给新的聚合节,赋给输入模块定义的每个节,以及赋给输入模块定义的每一个符号。当这一步完成时,程序中的每条指令和全局变量都有唯一的运行时内存地址了。 5.6 hello的执行流程程序名称:程序地址ld-2.27.so!_start 0x7fd7:8dfda090ld-2.27.so!_dl_start 0x7fd7:8dfdaea0ld-2.27.so!_dl_start_user 0x7fd7:8dfda09bld-2.27.so!_dl_init 0x7fd7:8dfe9630hello!_start 0x400500libc-2.27.so!__libc_start_main 0x7fd7:8dc09ab0-libc-2.27.so!__cxa_atexit 0x7fd7:8dc2b430-libc-2.27.so!__libc_csu_init 0x4005c0hello!_init 0x400488libc-2.27.so!_setjmp 0x7fd7:8dc26c10-libc-2.27.so!_sigsetjmp 0x7fd7:8dc28e2b–libc-2.27.so!__sigjmp_save 0x7fd7:8dc2db30hello!main 0x400532hello!puts@plt 0x4004b0hello!exit@plt 0x4004e0
hello!printf@plt – hello!sleep@plt –hello!getchar@plt –ld-2.27.so!_dl_runtime_resolve_xsave 0x7fd7:8dc324d0-ld-2.27.so!_dl_fixup 0x7fd7:8dc34520–ld-2.27.so!_dl_lookup_symbol_x 0x7fd7:8dd24dc0libc-2.27.so!exit 0x7fd7:8dd32fd0  5.7 Hello的动态链接分析调用dl_init之前,全局偏移量表 调用dl_init之后,全局偏移量表  具体操作请看下两张图片:   动态链接       5.8 本章小结本章主要介绍了链接的主要概念及其命令,以及链接后生成的可执行文件与可重定位目标文件的不同之处。同时,通过edb展示了hello的虚拟空间地址,了解了hello的执行流程(函数调用流程),并展示了dl_init运行前后全局偏移量表的变化。最后,解析了hello的动态链接过程。 
第6章 hello进程管理6.1 进程的概念与作用进程:一个具有一定独立功能的程序关于某个数据集合的一次运行活动,是系统进行资源分配和调度运行的基本单位 进程的状态:1.运行进程要么在cpu上运行,要么在等待被执行并且最终会被内核调度2.停止进程的执行被挂起,且不会被调度。当收到SIGSTOP,SIGTSTP,SIGTTIN或者SIGTTOU信号时,进程就停止,并且保持停止直到它收到一个SIGCONT信号,在这个时刻,进程再次开始运行。3.终止进程永远的停止了,原因可能有三:1.收到一个终止信号2.从主程序返回3,调用exit函数 6.2 简述壳Shell-bash的作用与处理流程Shell俗称壳(用来区别于核),是指“为使用者提供操作界面”的软件(命令解析器)。它类似于DOS下的command.com和后来的cmd.exe。它接收用户命令,然后调用相应的应用程序。Shell的功能:常用命令cat 文件名 输出文件内容到基本输出(屏幕 or 加>fileName 到另一个文件)cb 格式化源代码chmod //change mode,改变文件的权限cp copydate 当前的时间和日期echo a b c 在 变 量 赋 值 之 后 , 只 需 在 变 量 前 面 加 一 个 abc 在变量赋值之后,只需在变量前面加一个 abc去引用.lint 语法检查程序ls dirman helpmore typedu 查看磁盘空间状况ps 查看当前进程状况who 你的用户名和终端类型定义变量 name=abc? (bash/pdksh) || set name = abc (tcsh)mkdir 创建目录rmdir 删除目录cd 进入目录rm 删除文件more 显示文件echo 显示指定文本mv 改文件名 /移动文件pwd 显示目录路径命令shell的处理流程:shell 命令重新初始化用户的登录会话。当给出该命令时,就会重新设置进程的控制终端的端口特征,并取消对端口的所有访问。然后 shell 命令为用户把进程凭证和环境重新设置为缺省值,并执行用户的初始程序。根据调用进程的登录用户标识建立所有的凭证和环境。6.3 Hello的fork进程创建过程在终端Terminal中键入 ./hello 1180300403 wangxinlei 1,终端读入这个字符串,然后对这个字符串进行解析,因为hello不是一个内置的命令所以解析之后终端程序判断执行hello,终端首先会调用fork函数创建一个新的运行的子进程,子进程得到与父进程用户级虚拟地址空间相同的但是独立的一份副本,父进程与子进程之间最大的区别在于它们拥有不同的PID。内核能够以任意方式交替执行它们的逻辑控制流的指令。在子进程执行期间,父进程默认选项是显示等待子进程的完成。6.4 Hello的execve过程可执行文件被Execve加载并运行,其中execve函数带有参数列表argv和环境变量列表envp。它在加载文件后,创建了一组新的代码与数据,并初始化新的栈和堆段为0,将虚拟地址空间中的页映射到可执行文件的页大小的片,栈和堆段被初始化为可执行文件中的数据。6.5 Hello的进程执行 Hello的并发进程执行6.6 hello的异常与信号处理 正常执行 输入ctrl+c 输入ctrl+z ctrl+z后ps,jobs,pstree,fg并停止       ctrl+z后kill再ps   6.7本章小结本章节主要介绍了hello可执行文件载入内存并被执行的过程。首先shell调用execve函数,execve为其分配进程、内存,加载虚拟地址,初始化堆栈,然后开始运行,进程结束后将其回收,hello执行完成。 (第6章1分)
第7章 hello的存储管理7.1 hello的存储器地址空间物理地址(physical address)
用于内存芯片级的单元寻址,与处理器和CPU连接的地址总线相对应。
逻辑地址(logical address)
Intel为了兼容,将远古时代的段式内存管理方式保留了下来。逻辑地址指的是机器语言指令中,用来指定一个操作数或者是一条指令的地址。如上述汇编代码中所有的内存操作数均为逻辑地址。 线性地址(linear address)或也叫虚拟地址(virtual address)
跟逻辑地址类似,它也是一个不真实的地址,如果逻辑地址是对应的硬件平台段式管理转换前地址的话,那么线性地址则对应了硬件页式内存的转换前地址。 7.2 Intel逻辑地址到线性地址的变换-段式管理一个逻辑地址由两部份组成,段标识符: 段内偏移量。段标识符是由一个16位长的字段组成,称为段选择符。其中前13位是一个索引号。后面3位包含一些硬件细节,最后两位涉及权限检查,索引号,或者直接理解成数组下标 ,为段描述符的索引。段描述符具体地址描述了一个段,这样,很多个段描述符,就组了一个数组,叫“段描述符表”,这样,可以通过段标识符的前13位,直接在段描述符表中找到一个具体的段描述符,这个描述符就描述了一个段。首先,给定一个完整的逻辑地址[段选择符:段内偏移地址],
1、看段选择符的T1=0还是1,知道当前要转换是GDT中的段,还是LDT中的段,再根据相应寄存器,得到其地址和大小。我们就有了一个数组了。
2、拿出段选择符中前13位,可以在这个数组中,查找到对应的段描述符,这样,它了Base,即基地址就知道了。
3、把Base + offset,就是要转换的线性地址了。 7.3 Hello的线性地址到物理地址的变换-页式管理CPU的页式内存管理单元,负责把一个线性地址,最终翻译为一个物理地址。从管理和效率的角度出发,线性地址被分为以固定长度为单位的组,称为页 (page),例如一个32位的机器,线性地址最大可为4G,可以用4KB为一个页来划分,这页,整个线性地址就被划分为一个 tatol_page[2^20]的大数组,共有2的20个次方个页。这个大数组我们称之为页目录。目录中的每一个目录项,就是一个地址——对应的页的地址。 页式管理7.4 TLB与四级页表支持下的VA到PA的变换CPU 产生虚拟地址 VA,VA 传送给 MMU,MMU 使用前 36 位 VPN作为 TLB+TLBI向 TLB 中匹配,如果命中,则得到 PPN与 VPO组合成 PA。如果 TLB 中没有命中,MMU 向页表中查询,CR3 确定第一级页表的起始地址,VPN1确定在第一级页表中的偏移量,查询出 PTE,如果在物理内存中且权限符合,确定第二级页表的起始地址,以此类推,最终在第四级页表中查询到 PPN,与 VPO 组合成 PA,并且向 TLB 中添加条目。 Corei7内存系统7.5 三级Cache支持下的物理内存访问Cpu发出一个虚拟地址到TLB里搜索,如果命中,直接发送到L1 cache,若未命中,在页表中加载后再返回。L1中寻找物理地址时若未命中,就到L2与L3中插找。 三级cache下物理内存访问7.6 hello进程fork时的内存映射当shell程序运行fork为hello分配一个进程时,分配给它一个唯一的PID,从硬盘里调取hello的页表载入内存,初始化所有映射有效值为0,将两个进程中的每个页面都标记为只读,并将两个进程中的每个区域结构都标记为私有的写时复制。7.7 hello进程execve时的内存映射Execve函数在当前进程中加载并运行包含在可执行目标文件hello中的程序,用hello有效地替代了当前程序,加载hello需要这么几个步骤1. 删除已存在的用户区域,删除当前进程虚拟地址的用户部分中已存在的区域结构。2. 映射私有区域,为新程序的代码、数据、bss和站区域创建新的区域结构。所有这些新的区域都是私有的,写时复制的。3. 映射共享区域4. 设置程序计数器,使之指向代码区域的入口点7.8 缺页故障与缺页中断处理  发生缺页故障后,程序将牺牲一个页面,用于加载当前所需的页表项。 缺页处理 故障处理 故障处理7.9动态存储分配管理 动态内存分配器维护着一个进程的虚拟内存区域,称为堆。系统之间细节不同,但是不是通用性,假设堆是一个请求二进制堆的区域,它紧接在未初始化的数据区域后开始,并向上生长(向更高的地址)。对于每个进程,内核维护着一个变量 brk(读作 break),它指向堆的顶部。分配器将堆视为一组不同大小的块的集合来维护。每个块就是一个连续的虚拟内存片,要么是已分配的,要么是空闲的。已分配的块显式地保留为供应用程序使用。空闲块可用来分配。空闲块保持空闲,直到它显式的被被应用程序分配。一个分配的块将保持已分配状态,直到它被释放。   堆的位置。7.10本章小结本章主要介绍了计算机内部存储空间的管理方法。首先介绍了存储器地址空间包含的几种地址索引,然后分别介绍了段式管理与页式管理的方法,其中重点介绍了页式管理的内存访问以及程序运行过程中的内存映射。最后介绍了缺页故障与动态内存分配的原理与处理方法
第8章 hello的IO管理8.1 Linux的IO设备管理方法输入/输出是在主存和外部设备(例如磁盘驱动器、终端和网络之间复制数据的过程。所有的I/O设备都被摸醒华为文件,而所有的输入和输出都被当做对相应文件的读和写来执行。这种将设备优雅地映射为文件的方式,允许Linux内核引出一个简单、低级的应用接口,称为Unix I/O,这使得所有的输入和输出都能以一种统一且简单的方式来执行。 8.2 简述Unix IO接口及其函数1.打开文件和关闭文件。一个应用程序通过要求内核打开相应的文件,来宣告它想要访问一个I/O设备。内核返回一个小的非负整数,叫做描述符,它在后续对此文件的所有操作中标识这个文件。2.Linux shell创建的进程开始时都有三个打开的文件:标准输入(描述符为0)、标准输出(描述符为1)和标准错误(描述符为2)。头文件<unistd.h>定义了常量,它们可以用来代替显式的描述符值3.改变当期那文件位置4.读写文件5.关闭文件open函数  函数原型  int open(char *  path,int  oflag,…) ,返回值是一个文件描述符  , path顾名思义就是文件名 , oflage文件是打开方式  , 第三个形参应用于创建文件时使用,open函数使用if  判断的时候注意小细节read函数   函数原型  : ssize_t   read(int fd  ,   void
buf , size_t nbytes)    返回值是文件读取字节数 。 在好几种情况下会出现返回值不等于文件读取字节数 ,也就是第三个参数nbytes的情况 。 第二个形参buf读取到buf的内存 , 文件偏移量(current  file offset)受改变  。write函数   函数原型  ssize_t  write(int fd , const  void
buf, size_t nbytes),   返回值是文件写入字节数  ,  fd是文件描述符  ,将buf内容写入nbytes个字节到文件  但这里需要注意默认情况是需要在系统队列中等待写入(打开方式不同也会不同) 。以上三个出错都返回-1。lseek函数off_t lseek(int fd, off_t offset , int whence)  , 返回值成功函数返回新的文件偏移量 , 失败-1  , fd文件描述符  , off_t是有符号的整数  ,whence其实是和off_t配套使用的 , SEEK_SET文件开始处 ,  SEEK_CUR当前值的相对位置  SEEK_END文件长度±  close函数原型 , int close(int fd)   , 返回值 :成功返回0 , 失败—1    关闭文件描述符 8.3 printf的实现分析函数原型:int printf(const char fmt, …)
{
int i;
char buf[256];
   
     va_list arg = (va_list)((char
)(&fmt) + 4);
     i = vsprintf(buf, fmt, arg);
     write(buf, i);
   
     return i;
    }c语言中,参数压栈方式为从右向左,也就是说调用printf时最右边的参数先入栈,fmt是指向第一个const参数的指针,因此(char *)((&fmt)+4)表示的是第一个参数的地址。Vsprintf返回打印出来的字符串长度,Write将buf中i个元素的值写到终端。Write将要打印的字符串传入OS,然后OS调用一些其他的库更新刷新频率,完成输出操作。从vsprintf生成显示信息,到write系统函数,到陷阱-系统调用 int 0x80或syscall.字符显示驱动子程序:从ASCII到字模库到显示vram(存储每一个点的RGB颜色信息)。显示芯片按照刷新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点(RGB分量)。8.4 getchar的实现分析 getchar函数每次从缓冲区中得到一个字符。getchar()是stdio.h中的库函数,它的作用是从stdin流中读入一个字符,也就是说,如果stdin有数据的话不用输入它就可以直接读取了,第一次getchar()时,确实需要人工的输入,但是如果你输了多个字符,以后的getchar()再执行时就会直接从缓冲区中读取了。实际上是 输入设备->内存缓冲区->程序getchar  你按的键是放进缓冲区了,然后供程序getchar  getchar等调用read系统函数,通过系统调用读取按键ascii码,直到接受到回车键才返回。8.5本章小结本章主要介绍了系统级I/O的实现方法:以文件形式管理;并介绍了几个常用的Unix i/o接口函数,然后分析了printf和getchar 的实现。 结论Hello的一生是复杂且坎坷的。它通过预处理,编译,链接,一步步的转化为可执行程序。操作系统运用shell为他分配进程,虚拟内存。为了提高效率,我们运用虚拟内存页表存储、多级缓存协同工作、动态内存分配中的显隐式空闲链表、分时间片并发运行等管理策略。程序和操作系统是一个密不可分的整体,程序没有操作系统就是一盘散沙。程序好比战场上的士兵,而操作系统就是那个统领全局的将军。只有将军有好的策略,他的士兵才能同仇敌忾,万众一心,紧密合作,步步为营。这个将军让士兵们轮流执行他们的程序,而且时刻准备应对战场上的风云变化,时刻准备着处理任何异常。在紧急的情况下,将军还会赋予它的士兵更高的权限以应对眼前更复杂的情况(内核模式)。将军为了提高作战效率,还会让他的士兵们共同进攻(并行)。而程序的预处理,编译,链接,变为可执行文件就好比训练一个士兵,让它有了足以作战的能力。通过将军和士兵的密切配合,才打出了一场精妙绝伦的程序运行之仗。
附件Hello.i:预处理后的文件Hello.s:汇编文件Hello.o:可重定位目标文件Hello:可执行文件Hello.elf: 可重定位目标文件elf 
参考文献  1  林来兴. 空间控制技术[M]. 北京:中国宇航出版社,1992:25-42. 2  辛希孟. 信息技术与信息服务国际研讨会论文集:A集[C]. 北京:中国科学出版社,1999. 3  赵耀东. 新时代的工业工程师[M/OL]. 台北:天下文化出版社,1998 [1998-09-26]. http://www.ie.nthu.edu.tw/info/ie.newie.htm(Big5). 4  谌颖. 空间交会控制理论与方法研究[D]. 哈尔滨:哈尔滨工业大学,1992:8-13.[5]  KANAMORI H. Shaking Without Quaking[J]. Science,1998,279(5359):2063-2064.[6]  CHRISTINE M. Plant Physiology: Plant Biology in the Genome Era[J/OL]. Science,1998,281:331-332[1998-09-23]. http://www.sciencemag.org/cgi/ collection/anatmorp.[7] https://blog.csdn.net/happyforever91/article/details/51713741[8] https://blog.csdn.net/z3410218746/article/details/7563379(参考文献0分,缺失 -1分)

欢迎使用Markdown编辑器

你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。

新的改变

我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:

  1. 全新的界面设计 ,将会带来全新的写作体验;
  2. 在创作中心设置你喜爱的代码高亮样式,Markdown 将代码片显示选择的高亮样式 进行展示;
  3. 增加了 图片拖拽 功能,你可以将本地的图片直接拖拽到编辑区域直接展示;
  4. 全新的 KaTeX数学公式 语法;
  5. 增加了支持甘特图的mermaid语法1 功能;
  6. 增加了 多屏幕编辑 Markdown文章功能;
  7. 增加了 焦点写作模式、预览模式、简洁写作模式、左右区域同步滚轮设置 等功能,功能按钮位于编辑区域与预览区域中间;
  8. 增加了 检查列表 功能。

功能快捷键

撤销:Ctrl/Command + Z
重做:Ctrl/Command + Y
加粗:Ctrl/Command + B
斜体:Ctrl/Command + I
标题:Ctrl/Command + Shift + H
无序列表:Ctrl/Command + Shift + U
有序列表:Ctrl/Command + Shift + O
检查列表:Ctrl/Command + Shift + C
插入代码:Ctrl/Command + Shift + K
插入链接:Ctrl/Command + Shift + L
插入图片:Ctrl/Command + Shift + G
查找:Ctrl/Command + F
替换:Ctrl/Command + G

合理的创建标题,有助于目录的生成

直接输入1次#,并按下space后,将生成1级标题。
输入2次#,并按下space后,将生成2级标题。
以此类推,我们支持6级标题。有助于使用TOC语法后生成一个完美的目录。

如何改变文本的样式

强调文本 强调文本

加粗文本 加粗文本

标记文本

删除文本

引用文本

H2O is是液体。

210 运算结果是 1024.

插入链接与图片

链接: link.

图片: Alt

带尺寸的图片: Alt

居中的图片: Alt

居中并且带尺寸的图片: Alt

当然,我们为了让用户更加便捷,我们增加了图片拖拽功能。

如何插入一段漂亮的代码片

博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片.

// An highlighted block
var foo = 'bar';

生成一个适合你的列表

  • 项目
    • 项目
      • 项目
  1. 项目1
  2. 项目2
  3. 项目3
  • 计划任务
  • 完成任务

创建一个表格

一个简单的表格是这么创建的:

项目Value
电脑$1600
手机$12
导管$1

设定内容居中、居左、居右

使用:---------:居中
使用:----------居左
使用----------:居右

第一列第二列第三列
第一列文本居中第二列文本居右第三列文本居左

SmartyPants

SmartyPants将ASCII标点字符转换为“智能”印刷标点HTML实体。例如:

TYPEASCIIHTML
Single backticks'Isn't this fun?'‘Isn’t this fun?’
Quotes"Isn't this fun?"“Isn’t this fun?”
Dashes-- is en-dash, --- is em-dash– is en-dash, — is em-dash

创建一个自定义列表

Markdown
Text-to- HTML conversion tool
Authors
John
Luke

如何创建一个注脚

一个具有注脚的文本。2

注释也是必不可少的

Markdown将文本转换为 HTML

KaTeX数学公式

您可以使用渲染LaTeX数学表达式 KaTeX:

Gamma公式展示 Γ ( n ) = ( n − 1 ) ! ∀ n ∈ N \Gamma(n) = (n-1)!\quad\forall n\in\mathbb N Γ(n)=(n1)!nN 是通过欧拉积分

Γ ( z ) = ∫ 0 ∞ t z − 1 e − t d t   . \Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,. Γ(z)=0tz1etdt.

你可以找到更多关于的信息 LaTeX 数学表达式here.

新的甘特图功能,丰富你的文章

Mon 06 Mon 13 Mon 20 已完成 进行中 计划一 计划二 现有任务 Adding GANTT diagram functionality to mermaid
  • 关于 甘特图 语法,参考 这儿,

UML 图表

可以使用UML图表进行渲染。 Mermaid. 例如下面产生的一个序列图:

张三 李四 王五 你好!李四, 最近怎么样? 你最近怎么样,王五? 我很好,谢谢! 我很好,谢谢! 李四想了很长时间, 文字太长了 不适合放在一行. 打量着王五... 很好... 王五, 你怎么样? 张三 李四 王五

这将产生一个流程图。:

链接
长方形
圆角长方形
菱形
  • 关于 Mermaid 语法,参考 这儿,

FLowchart流程图

我们依旧会支持flowchart的流程图:

Created with Raphaël 2.2.0 开始 我的操作 确认? 结束 yes no
  • 关于 Flowchart流程图 语法,参考 这儿.

导出与导入

导出

如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到 文章导出 ,生成一个.md文件或者.html文件进行本地保存。

导入

如果你想加载一篇你写过的.md文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,
继续你的创作。


  1. mermaid语法说明 ↩︎

  2. 注脚的解释 ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值