HIT CSAPP hello的一生

计算机系统基础 大作业  题     目  程序人生-Hello’s P2P  专       业   机电学院飞行器制造专业               学     号    1160801103                    班     级     1608302                   学       生       付振宇              指 导 教 师       史先俊                      计算机科学与技术学院2019年3月摘  要摘要是论文内容的高度概括,应具有独立性和自含性,即不阅读论文的全文,就能获得必要的信息。摘要应包括本论文的目的、主要内容、方法、成果及其理论与实际意义。摘要中不宜使用公式、结构式、图表和非公知公用的符号与术语,不标注引用文献编号,同时避免将摘要写成目录式的内容介绍。 关键词:关键词1;关键词2;……;                             (摘要0分,缺失-1分,根据内容精彩称都酌情加分0-1分)本文主要是通过合理运用这个学期在计算机系统课程上学习的知识,分析研究hello程序在Linux下的P2P和020过程,通过熟练使用各种工具,学习Linux框架下整个程序的声明周期,加深对课本知识的印象。      
目  录 第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简介根据Hello的自白,利用计算机系统的术语,简述Hello的P2P,020的整个过程。P2P:即from program to process。程序员输入hello.c文件,经cpp预处理变成hello.i,ccl编译生成hello.s,,as汇编成hello.o,ld链接最终生成可执行目标程序hello。之后在shell中输入./hello运行hello程序,shell fork产生子进程,便完成from program to process. 020:From Zero to Zero. 调用execve 函数在新的子进程中加载并运行 hello,调用_start函数,之后转移到hello的main函数,CPU 为运行的 hello 分配时间片执行逻辑 控制流。当程序运行结束后, 终止的hello进程被父进程bash回收。1.2 环境与工具列出你为编写本论文,折腾Hello的整个过程中,使用的软硬件环境,以及开发与调试工具。硬件环境:Intel® Core™ i7-6700HQ CPU 2.60GHZ 8G RAM软件环境:Windows 10 64 位操作系统;开发与调试工具:VMware 14;Ubuntu 16.04 LTS;gcc; edb; readelf; objdump; gedit; CodeBlocks 17.12  1.3 中间结果列出你为编写本论文,生成的中间结果文件的名字,文件的作用等。hello.ihello预处理之后的文本文件hello.shello编译之后的汇编文件hello.ohello汇编之后的可重定位目标文件hellohello链接之后的可执行目标文件hello.objdumphello的反汇编代码hello.elfhello的ELF文件信息helloo.objdmphello.o的反汇编代码helloo.elfHello.o 的 ELF 格式  1.4 本章小结本章简要介绍了hello的P2P,O2O过程,并列出了本次实验的环境和中间结果(第1章0.5分)  
第2章 预处理2.1 预处理的概念与作用预处理又称预编译,(对于c/c++来说)预处理指的是在程序编译之前,根据以字符#开头的命令(即头文件/define/ifdef之类的),修改原始的c程序,例如大作业所提供的hello.c文件,就有三个头文件:stdio.h,unistd.h,stdlib.h预处理的作用:1. 执行源文件包含。#include 指令告诉预处理器(cpp)读取源程序所引用 的系统源文件,并把源文件直接插入程序文本中。2. 执行宏替换。用实际值替换用#define 定义的字符串3. 条件编译。根据#if 后面的条件决定需要编译的代码 , #endif 是#if, #ifdef, #ifndef 这些条件命令的结束标志。2.2在Ubuntu下预处理的命令   2.3 Hello的预处理结果解析此时hello.i有3188行,下图为main函数所在     原文件中的宏进行了宏展开,头文件中的内容被包含进该文件中。 2.4 本章小结本阶段完成了对hello.c的预处理工作。介绍了预处理的定义与作用、并结合预处理之后的程序对预处理结果进行了解析。(第2章0.5分)
第3章 编译3.1 编译的概念与作用 注意:这儿的编译是指从 .i 到 .s 即预处理后的文件到生成汇编语言程序编译程序也称为编译器,是指把用高级程序设计语言书写的源程序,翻译成等价的汇编语言格式目标程序的翻译程序。编译器将文本文件 hello.i 翻译成文本文件 hello.s,这个过程称为编译。          3.2 在Ubuntu下编译的命令  3.3 Hello的编译结果解析 (以下格式自行编排,编辑时删除) 此部分是重点,说明编译器是怎么处理C语言的各个数据类型以及各类操作的。应分3.3.1~ 3.3.x等按照类型和操作进行分析,只要hello.s中出现的属于大作业PPT中P4给出的参考C数据与操作,都应解析。Hello.s内容如下:.file “hello.c” .text .globl sleepsecs .data .align 4 .type sleepsecs, @object .size sleepsecs, 4sleepsecs: .long 2 .section .rodata .align 8.LC0: .string “\347\224\250\346\263\225: Hello \345\255\246\345\217\267 \345\247\223\345\220\215\357\274\201”.LC1: .string “Hello %s %s\n” .text .globl main .type main, @functionmain:.LFB5: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 subq $32, %rsp movl %edi, -20(%rbp) movq %rsi, -32(%rbp) cmpl $3, -20(%rbp) je .L2 leaq .LC0(%rip), %rdi call puts@PLT movl $1, %edi call exit@PLT.L2: movl $0, -4(%rbp) jmp .L3.L4: movq -32(%rbp), %rax addq $16, %rax movq (%rax), %rdx movq -32(%rbp), %rax addq $8, %rax movq (%rax), %rax movq %rax, %rsi leaq .LC1(%rip), %rdi movl $0, %eax call printf@PLT movl sleepsecs(%rip), %eax movl %eax, %edi call sleep@PLT addl $1, -4(%rbp).L3: cmpl $7, -4(%rbp) jle .L4 call getchar@PLT movl $0, %eax leave .cfi_def_cfa 7, 8 ret .cfi_endproc.LFE5: .size main, .-main .ident “GCC: (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0” .section .note.GNU-stack,"",@progbits3.3.1数据1.字符串.LC0: .string “\347\224\250\346\263\225: Hello \345\255\246\345\217\267 \345\247\223\345\220\215\357\274\201”.LC1: .string "Hello %s %s\n"对应原c文件中"Usage: Hello 学号 姓名!\n"其中中文已被编码为UTF-8 格式  一个汉字占3个字节2).LC1: .string "Hello %s %s\n"对应原c文件中"Hello %s %s\n"第二个printf中的格式化参数其中后两个字符串已在.rodata中声明2.整数1).globl sleepsecs.type sleepsecs, @object .size sleepsecs, 4sleepsecs: .long 2 .section .rodata这个是已经赋值的全局变量,编译器处理时在.data 节声明该变量,.data 节存放已经初始化的全局和静态 C 变量。因为是整型,所以后面给它赋的size是4个字节又设置了long类型其值为2.2)int i根据cmpl $7, -4(%rbp)  编译器将i存到了-4(%rbp) 中,且占4个字节3)int argc作为第一个参数被压栈pushq %rbp传入main函数4)立即数其他整型都是以立即数的形式出现3.数组 char *argv[].L4: movq -32(%rbp), %rax addq $16, %rax movq (%rax), %rdx movq -32(%rbp), %rax addq $8, %rax movq (%rax), %rax这是一个指针数组,从上面数组相关的指令也可以看出来,一个内容占8个字节,说明linux中一个地址的大小是8个字节3.3.2赋值1)全局变量直接在.data中被声明为long类型值为2(因为int类型忽略掉了小数部分)2) i=0 通过mov指令将0赋给了i而因为i为4字节的整数值,所以用了后缀l3.3.3算术操作1)i++addl $1, -4(%rbp)通过这个指令每次将i的值加一3.3.4 关系判断1)argc!=3 先将argc的值传入-20(%rbp) 的位置,最后与3比较。判断是否跳转L22)i<10cmpl $7, -4(%rbp) jle .L4过比较i与7的值,如果i小于等于7,则跳转L4继续执行循环里的内容否则退出循环3.3.5控制转移1)if(argc!=3)cmpl $3, -20(%rbp)je .L2首先 cmpl 比较 argv 和 3,设置条件码,使用 je 判断 ZF 标志位,如果为 0,说明 argv-3=0 argv==3,则不执行 if 中的代码直接跳转到.L2,否则 顺序执行下一条语句,即 执行 if 中的代码。2)for(i=0;i<10;i++)addl $1, -4(%rbp)cmpl $7, -4(%rbp)jle .L4使用 cmpl 进行比较,如果 i<=7,则跳入.L4 for循环体执行,否则说明循环结束,顺序执行for之后的逻辑。3.3.6函数函数的调用需要有以下过程:传递控制、数据传递、分配空间1)main函数a.main函数被系统启动函数 __libc_start_main 调用,call指令将main函数的地址分配给%rip,随后调用main函数。b.main函数有两个参数argc *argv[],分别使用%rdi 和%rsi 存储,函数正常出口为 return 0,将%eax 设置 0 返回。c.使用%rbp 记录栈帧的底,函数分配栈帧空间,最后使用leave指令将栈恢复为调用之前的状态(leave相当于mov %rbp %rsp)最后ret返回将下一条指令地址设置为%rip2)printf函数a.第一printf将%rdi 设置为“Usage: Hello 学号 姓名! \n”字符串的首地址。第二次 printf 设置%rdi 为“Hello %s %s\n”的首地址,设置%rsi 为 argv[1],%rdx为argv[2]。b.第一次 printf 因为只有一个字符串参数,所以 call puts@PLT;第二次 printf 使用 call printf@PLT。3)exit函数a.movl $1, %edi将edi设置为1b.call exit@PLT  call调用exit4)sleep函数a.movl sleepsecs(%rip), %eaxmovl %eax, %edi将%edi 设置为 sleepsecsb.call sleep@PLT5)getchar 函数a.call getchar@PLT3.4 本章小结 本章主要介绍了编译器是如何处理C程序中数据和操作。通过查汇编指令,深入理解机器如何处理C语言的输入和操作。(第3章2分)
第4章 汇编4.1 汇编的概念与作用汇编器(as)将.s 汇编程序翻译成机器语言指令,把这些指令打包成可重定位 目标程序的格式,并将结果保存在.o 目标文件中,.o 文件是一个二进制文件,它包含程序的指令编码。这个过程称为汇编,亦即汇编的作用。注意:这儿的汇编是指从 .s 到 .o 即编译后的文件到生成机器语言二进制程序的过程。4.2 在Ubuntu下汇编的命令应截图,展示汇编过程! 4.3 可重定位目标elf格式    分析hello.o的ELF格式,用readelf等列出其各节的基本信息,特别是重定位项目分析。使用 readelf 获得 hello.o 的 elf 格式:readelf -a hello.o > hello.elf。接下来分析 可重定位文件 hello.o 的 elf 格式: 名称作用ELF头       描述了生成该文件的系统的大小和字节顺序以及帮助链接器语法分析和解释目标文件的信息.text已编译的程序的机器代码.rodata只读数据.data已初始化的全局和静态C变量.bss未初始化的全局和静态C变量.symtab一个符号表,存放在程序中定义和引用的函数和全局变量的信息.rel.text.text节的重定位记录表.rel.data被模块引用或定义的所有全局变量的重定位信息.debug一个调试符号表.line原始C源程序的行号和.text节中机器指令之间的映射.strtab一个字符串表节头部表每个节的偏移量大小使用readelf –h hello.o查看文件头信息。根据文件头的信息,可以知道该文件是可重定位目标文件,有13个节 使用readelf –S hello.o查看节头表。从而得知各节的大小,以及他们可以进行的操作 使用readelf –s hello.o可以查看符号表的信息 因为是可重定位目标文件,所以每个节都从0开始,用于重定位。在文件头中得到节头表的信息,然后再使用节头表中的字节偏移信息得到各节在文件中的起始位置,以及各节所占空间的大小。同时可以观察到,代码段是可执行的,但是不能写;数据段和只读数据段都不可执行,而且只读数据段也不可写。4.4 Hello.o的结果解析(以下格式自行编排,编辑时删除)objdump -d -r hello.o  分析hello.o的反汇编,并请与第3章的 hello.s进行对照分析。Hello.o反汇编后出现机器码,方便于机器直接识别指令跳转语句,比如call函数反汇编前call的是L1,L2,而反汇编后call具体的地址函数调用:call后面的函数调用从.s文件中直接call函数的名字变成了call下一条语句的地址。这是由于许多函数需要从链接的库中调用,但还不知道他们的具体地址,所以call只能将他们的相对地址全都设置为0,在.rela.text中为他们设置重定位条目,等待静态链接的进一步确定。   4.5 本章小结 本阶段完成了对hello.s的汇编工作。使用Ubuntu下的汇编指令可以将其转换为.o可重定位目标文件。此外,本章通过将.o文件反汇编结果与.s汇编程序代码进行比较,了解了二者之间的差别。完成该阶段转换后,可以进行下一阶段的链接工作。(第4章1分)
第5章 链接5.1 链接的概念与作用链接是将各种代码和数据片段收集并组合成为一个单一文件的过程,这文件可被加载到内存并执行。链接可以执行于编译时,也就是在源代码被翻译成机器代码时,也可以执行于加载时,也就是在程序被加载器加载到内存并执行时;甚至执行于运行时,也就是由应用程序来执行。注意:这儿的链接是指从 hello.o 到hello生成过程。5.2 在Ubuntu下链接的命令使用ld的链接命令,应截图,展示汇编过程! 注意不只连接hello.o文件5.3 可执行目标文件hello的格式分析hello的ELF格式,用readelf等列出其各段的基本信息,包括各段的起始地址,大小等信息。 在 ELF 格式文件中,Section Headers 对 hello 中所有的节信息进行了声明,其 中包括大小 Size 以及在程序中的偏移量 Offset,因此根据 Section Headers 中的信 息我们就可以用 HexEdit 定位各个节所占的区间(起始位置,大小)。其中 Address 是程序被载入到虚拟地址的起始地址。5.4 hello的虚拟地址空间使用edb加载hello,查看本进程的虚拟地址空间各段信息,并与5.3对照分析说明。    在edb中打开hello  查看data dump窗口 可以看出程序的地址是从0x40000加载的    0x400ff0结束再看elf文件中的program headers:每一个表项都提供了各段在虚拟地址空间和物理地址空间的大小、位置、标志、访问权限和对齐方面的信息再看程序的八个段:PHDR:程序头表INTERP:程序执行前需要调用的解释器LOAD:程序目标代码和常量信息DYNAMIC:动态链接器所使用的信息NOTE::辅助信息GNU_EH_FRAME:保存异常信息GNU_STACK:使用系统栈所需要的权限信息GNU_RELRO:保存在重定位之后只读信息的位置5.5 链接的重定位过程分析对比hello和hello.o elf文件中的section headers,发现hello中多出了如下内容:.interp:保存ld.so的路径.note.ABI-tag Linux 下特有的 section.note.gnu.build-i:编译信息表.gnu.hash:gnu的扩展符号hash表.dynsym:动态符号表.dynstr:动态符号表中的符号名称.gnu.version:符号版本.gnu.version_r:符号引用版本.rela.dyn:动态重定位.rela.plt:.plt节的重定位条目.init:程序初始化.plt:动态链接表.fini:程序终止时需要的执行的指令.eh_frame:程序执行错误时的指令.dynamic:存放被ld.so使用的动态链接信息.got:存放程序中变量全局偏移.got.plt:存放程序中函数的全局偏移量.data:初始化过的全局变量或者声明过的函数(以下格式自行编排,编辑时删除)objdump -d -r hello 分析hello与hello.o的不同,说明链接的过程。结合hello.o的重定位项目,分析hello中对其怎么重定位的。与上一章的区别:1) 函数个数变多:链接后多了printf、sleep等函数2) 函数调用:call后面的指令已经变成了对应函数的正确地址3) 函数从.text节开始变成了从init节开始objdump -d -r hello 分析hello与hello.o的不同,说明链接的过程。结合hello.o的重定位项目,分析hello中对其怎么重定位的。5.6 hello的执行流程通过使用objdump查看反汇编代码,以及使用edb单步运行,可以找出.text节中main函数前后执行的函数名称。在main函数之前执行的程序有:_start、__libc_start_main@plt、__libc_csu_init、_init、frame_dummy、register_tm_clones。在main函数之后执行的程序有:exit、cxa_thread_atexit_impl、fini。5.7 Hello的动态链接分析   在edb调试之后我们发现原先的global_offset表是全0的状态,在执行过_dl_init之后被赋上了相应的偏移量的值。这说明dl_init操作是给程序赋上当前执行的内存地址偏移量,这是初始化hello程序的一步。分析hello程序的动态链接项目,通过edb调试,分析在dl_init前后,这些项目的内容变化。要截图标识说明。5.8 本章小结本章介绍了链接的概念和作用,分析了hello的ELF格式,虚拟地址空间的分配,重定位和执行过程还有动态链接的过程。(第5章1分) 
第6章 hello进程管理6.1 进程的概念与作用进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。进程为用户提供了以下假象:我们的程序好像是系统中当前运行的唯一程序一样,我们的程序好像是独占的使用处理器和内存,处理器好像是无间断的执行我们程序中的指令,我们程序中的代码和数据好像是系统内存中唯一的对象。6.2 简述壳Shell-bash的作用与处理流程shell是一个应用程序,他在操作系统中提供了一个用户与系统内核进行交互的界面。他的处理过程一般是这样的: 1读取用户的输入 2分析输入内容,获得输入参数 3如果是内核命令则直接执行,否则调用相应的程序执行命令 4在程序运行期间,shell需要监视键盘的输入内容,并且做出相应的反应6.3 Hello的fork进程创建过程在新创建的子进程中,execve函数加载并运行hello,且带参数列表argv和环境变量envp。在execve加载了hello之后,它调用_start,_start设置栈,并将控制传递给新程序的主函数。6.4 Hello的execve过程首先,要运行 hello 程序,需要在 shell 输入./hello 1160801103 fzy。运行的终端程序会 对输入的命令行进行解析,因为 hello不是内置 shell 命令所以终端判断./hello 的语义为执行当前目录下的可执行目标文件 hello,之后终端程序 首先会调用 fork 函数创建一个新的运行的子进程,新创建的子进程几乎但不完全与父进程相同,这就意味着,当父进程调用 fork 时,子进程可以读写父进程中打开的 任何文件。父进程与子进程之间最大的区别在于它们拥有不同的 PID。流程图如下: 6.5 Hello的进程执行1.上下文信息:上下文就是内核重新启动一个被抢占的进程所需要的状态,它由通用寄存器、浮点寄存器、程序寄存器、用户栈和各种内核数据结构等对象的值构成。2进程时间片:一个进程执行它的控制流的一部分的每个时间段叫做时间片。3进程调度:在进程执行的某个时刻,内核可以决定抢占当前进程,丙重新开始一个先前被抢占的进程,这种决策就叫做调度。4用户模式和内核模式:处理器通用使用一个寄存器提供两种模式的区分,该寄存器描述了进程当前享有的权利,当没有设置模式位时,进程就处于用户模式中,用户模式的进程不允许执行特权指令,也不允许直接引用地址空间中内核区的代码和数据;设置模式位时,进程处于内核模式,该进程可以执行指令集中的任何命令,并可以访问系统中的任何内存位置。看起来我们的程序在独占CPU,但事实上,我们知道我们的程序同时运行许多程序,这些程序在内核模式和用户模式中不断切换以执行多个程序。 6.6 hello的异常与信号处理1 正常执行2. 不停乱按,此时键盘输入的字符会被程序当做命令行执行,回车会被直接执行 3. 按ctrl +z,父进程接收SIGSTP,将程序挂起,并可以再次执行  4. Shell父进程接收SIGINT结束进程直接回收 hello执行过程中会出现哪几类异常,会产生哪些信号,又怎么处理的。 程序运行过程中可以按键盘,如不停乱按,包括回车,Ctrl-Z,Ctrl-C等,Ctrl-z后可以运行ps  jobs  pstree  fg  kill 等命令,请分别给出各命令及运行结截屏,说明异常与信号的处理。6.7本章小结本章介绍了进程的概念和作用,描述了shell如何在用户和系统内核之间建起一个交互的桥梁。讲述shell的基本操作以及各种内核信号和命令,还总结了shell是如何fork新建子进程、execve如何执行进程、hello进程如何在内核和前端中反复跳跃运行的。(第6章1分)
第7章 hello的存储管理7.1 hello的存储器地址空间结合hello说明逻辑地址、线性地址、虚拟地址、物理地址的概念。逻辑地址:程序代码经过编译后出现在汇编程序的地址。逻辑地址由选择符和偏移量组成。线性地址:地址空间中的整数是连续的,这样的地址空间就是线性地址空间。Hello程序中的地址都是线性的。虚拟地址:带虚拟内存的系统中,CPU从一个有N=2n个地址的地址空间中生成虚拟地址,这个地址空间就是虚拟地址空间。Hello的反汇编代码中使用的局势虚拟地址。物理地址:物理内存的实际地址。Hello实际执行时储存在内存中的地址就是物理地址。7.2 Intel逻辑地址到线性地址的变换-段式管理段式储存将程序地址分成若干段,为每个段分配连续的分区,而进程中的每个段可以不连续地存放在内存的不同分区中。程序加载时,操作系统为所有段分配内存。段式管理将一个程序分成若干段储存,它包括段号段名,段起点、段的长度等。7.3 Hello的线性地址到物理地址的变换-页式管理线性地址被分以固定长度为单位的组,称为页(page)例如一个32位的机器,线性地址最大为4G,整个地址被划分为2^20个页,称为页目录,目录中的每项就是页的地址另一类“页”叫物理页,或者页框、页桢。是分页单元把所有的物理内存也划分为固定长度的管理单位,它的长度一般与内存页是一一对应的。1、分页单元中将地址放在CPU的cr3寄存器中,是进行地址转换的开始点。2、每一个32位的线性地址被划分为三部份,面目录索引、页表索引、偏移。依据以下步骤进行转换:1、从cr3中取出进程的页目录地址;2、根据线性地址前十位,在数组中,找到对应的索引项,而页的地址被放到页表中去了。3、根据线性地址的中间十位,在数组中找到页的起始地址;4、将线性地址最后12位与页的起始地址相加,得到最终我们想要的地址; 7.4 TLB与四级页表支持下的VA到PA的变换 机器将虚拟地址VA分为VPN,VPO两部分,VPN又被分为TLBT和TLBI作为TLB的查询。根据TLBI确定TLB中的组索引,并根据TLBT判断PPN是否已被缓存到TLB中,如果TLB命中,则直接返回PPN,否则会到页表中查询PPN。在页表中查询PPN时,VPN被分为四级页表的索引,前三级页表的查询结果为下一级页表的基地址,第四级页表的查询结果为PPN。结合PPN与VPO得到物理地址PA 7.5 三级Cache支持下的物理内存访问 首先CPU发出一个虚拟地址,在TLB里面寻找。如果命中,那么将PTE发送给L1,否则先在页表中更新PTE。然后再进行L1根据PTE寻找物理地址,检测是否命中的工作。7.6 hello进程fork时的内存映射 mm_struct(内存描述符):描述一个进程的整个虚拟内存空间 vm_area_struct(区域结构描述符):描述进程的虚拟内存空间的一个区间 Fork函数为新进程创建虚拟内存。创建当前进程的的mm_struct, vm_area_struct和页表的原样副本。在新进程中返回时,新进程拥有与调用fork进程相同的虚拟内存,随后的写操作通过写时复制机制创建新页面。7.7 hello进程execve时的内存映射1. 删除已存在的用户区域2. 创建新的私有区域,为新程序的代码、数据、bss和栈区域创建新的区域结构3. 创建新的共享区域4. 设置PC指向代码的入口7.8 缺页故障与缺页中断处理段错误:判断这个缺页的虚拟地址是否合法,如果遍历所有的合法区域结构都无法匹配这个虚拟地址,就返回一个段错误(segment fault) 非法访问:查看地址的进程是否有读写改这个地址的权限。 情况3:如果上面两种情况都不符合就是正常缺页,那就选择一个牺牲页,然后换入新的页面并更新到页表。  7.9动态存储分配管理 在程序运行时,动态内存分配器给程序分配内存,动态内存分配器维护着一个进程的虚拟内存(堆)。分配出来的动态的内存在地址段中按照下图的位置给堆栈分配内存空间。这个称为堆。  malloc(size_t size)每次声明内存空间都要保证至少分配size_t大小的内存,保证双字对齐,从空闲块中分配空间,并在申请空间的时,将空闲的空间碎片合并,从而减少浪费。 显式空闲链表对空闲块的分配方法见下图: 7.10本章小结本章介绍了hello的内存管理,复习了与内存管理相关的重要的概念和方法。加深了对动态内存分配的认识和了解讲述了虚拟地址、物理地址、线性地址、逻辑地址的概念,还有进程fork和execve时的内存映射的内容。
第8章 hello的IO管理8.1 Linux的IO设备管理方法设备的模型化:所有的 IO 设备都被模型化为文件,而所有的输入和输出都被 当做对相应文件的读和写来执行,这种将设备优雅地映射为文件的方式,允许 Linux 内核引出一个简单低级的应用接口,称为 Unix I/O。设备管理:unix io接口1. 打开和关闭文件2. 读取和写入文件3. 改变当前文件的位置8.2 简述Unix IO接口及其函数8.3 printf的实现分析(以下格式自行编排,编辑时删除)1.open函数 打开文件:2.close函数 关闭文件3.read函数:read 函数从描述符为 fd 的当前文 件位置赋值最多 n 个字节到内存位置 buf4.write函数:从内存位置 buf 复制至多 n 个字节到描述符为 fd 的当前文件位置从vsprintf生成显示信息,到write系统函数,到陷阱-系统调用 int 0x80或syscall.字符显示驱动子程序:从ASCII到字模库到显示vram(存储每一个点的RGB颜色信息)。显示芯片按照刷新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点(RGB分量)。8.4 getchar的实现分析1. int getchar(void)  2. {  3.     char c;  4.     return (read(0,&c,1)==1)?(unsigned char)c:EOF  5. }  由代码知getchar函数通过调用read函数来读取字符。read函数有三个参数,第一个参数为文件描述符fd,fd为0表示标准输入;第二个参数为输入内容的指针;第三个参数为读入字符的个数。read函数的返回值为读入字符的个数,出错则返回-1。 当用户按键时,键盘接口会产生一个键盘扫描码和一个中断请求,中断处理程序会从键盘接口取得按键扫描码并把它转换成ASCII码,保存到系统的键盘缓冲区。read执行一个系统调用,按照系统调用从键盘缓冲区读取按键ASCII码,直到接受到回车键才返回。8.5本章小结本章节讲述了linux的I/O设备管理机制,了解了接口及相关函数,简单分析了printf和getchar函数的实现方法以及操作过程。(第8章1分)结论用计算机系统的语言,逐条总结hello所经历的过程。你对计算机系统的设计与实现的深切感悟,你的创新理念,如新的设计与实现方法。hello经过预处理、编译,汇编成二进制的hello.o,通过链接器生成可以被linux系统执行的二进制文件。在shell中通过指令 ./hello 执行hello。通过fork生成子进程。Hello也有许多理论优化,如PA的cache 和VA的TLB。hello的io设备也有着一套复杂的实现原则。在hello运行过程中,可以发送各种信号(如crtl+z挂起进程,发送ctrl+c信号结束进程)来控制它 。过程中还分析hello进程的内存空间和I/O机制。 在做大作业的过程中,回顾了整本书中计算机系统的知识,回顾了很多调试器比如edb,gdb,对整个程序的运行过程的认识更加清晰。(结论0分,缺失 -1分,根据内容酌情加分)
附件列出所有的中间产物的文件名,并予以说明起作用。hello.chello.ihello.shello.ohellohello.elf(附件0分,缺失 -1分)
参考文献为完成本次大作业你翻阅的书籍与网站等[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.(参考文献0分,缺失 -1分)[1]  兰德尔E.布莱恩特等. 深入理解计算机系统. 北京:机械工业出版社,2016:1-640.[2] getchar百度百科:https://baike.baidu.com/item/getchar/919709?fr=aladdin[3] LINUX 逻辑地址、线性地址、物理地址和虚拟地址https://www.cnblogs.com/zengkefu/p/5452792.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值