程序人生-Hello's P2P

题 目 程序人生-Hello’s P2P
专 业 计算机科学与技术
学   号 1180300220
班   级 1836101
学 生 崔涵    
指 导 教 师 刘宏伟

计算机科学与技术学院
2019年12月
摘 要
摘要:本文将通过介绍一个hello.c的源文件从开始执行到执行完毕的过程,分析编译器在对这个文件进行处理的预处理,编译,汇编,链接的每一个步骤,并同时分析相应时刻系统进行的一系列反应和操作。通过这个过程一窥整个计算机系统的运行机理。

关键词:预处理,汇编,链接,系统,进程,存储;

(摘要0分,缺失-1分,根据内容精彩称都酌情加分0-1分)

目 录

第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:首先,用gcc将hello.c源文件进行预处理得到hello.i,之后编译得到hello.s,汇编得到hello.o,再与其他.o文件链接,经过这一系列步骤后我们可以得到一个可执行目标文件。
020:在执行时,这个可执行文件可以被加载进内存。要执行这个可执行程序,我们需要在shell中输入这个可执行文件的名称,shell将fork一个新的进程,并将要执行的目标文件通过execve装载进内存。接下来,Cpu会从.text中逐条取指令执行。执行完毕后,shell或父进程将会回收这个进程,回收这个进程之后shell中将不会有这个进程的任何信息。
1.2 环境与工具
列出你为编写本论文,折腾Hello的整个过程中,使用的软硬件环境,以及开发与调试工具。
CPU:Inter(R) Core™ i5-8257U @1.4GHz(64位)
内存:16G
磁盘:512G SSD
软件环境:Ubuntu18.04 MacOS(10.15)
工具:gcc,edb,gdb,objdump,Visual Studio
1.3 中间结果
列出你为编写本论文,生成的中间结果文件的名字,文件的作用等。
Hello.i 预处理之后的文本文件
Hello.s 编译之后的汇编文件
Hello.o 汇编之后的可重定位文件
Hello 链接其他文件后的可执行目标文件
Asm1.txt hello.o的反汇编代码
Elf.txt 用readelf查看hello.o输出的txt文件。
1.4 本章小结
本章介绍了P2P,020,介绍了本次大作业的软硬件环境及中间结果。
(第1章0.5分)

第2章 预处理
2.1 预处理的概念与作用
概念:预处理器cpp根据以字符#开头的命令(宏定义、条件编译),修改原始的C程序,将引用的所有库展开合并成为一个完整的文本文件。
作用:

  1. 将源程序开头声明的头文件插入hello.c中,得到hello.i
  2. 对宏定义的内容进行对应处理。
    在这里插入图片描述
    2.2在Ubuntu下预处理的命令
    Gcc -E -o hello.i hello.c

在这里插入图片描述-o后接输出文件名
2.3 Hello的预处理结果解析
在这里插入图片描述

用vim打开hello.i可以看到,程序变成了3188行,原来出现在最开头的三个头文件和注释已经消失,已经被其他文本代替。

在这里插入图片描述所有头文件的代码都被写入了hello.i当中,这样hello.i才是可以独立运行的源代码。此外,编译器还将所有的注释删除了。
2.4 本章小结
本章对预处理得到的文件进行初步分析。通过预处理,将C文件变成了可以独立执行的文件,并删除注释。
(第2章0.5分)

第3章 编译
3.1 编译的概念与作用
概念:

  1. 利用编译程序从源语言编写的源程序产生目标程序的过程
  2. 用编译程序生成目标程序的动作。
    作用:将整理好的源代码转化为汇编语言。
    3.2 在Ubuntu下编译的命令
    Gcc -S -o hello.s hello.i

在这里插入图片描述汇编如下:
在这里插入图片描述
3.3 Hello的编译结果解析
3.3.1 对于变量的处理:
(以下结果为VS code中打开内容)
在这里插入图片描述
可以看到,文件从hello.i的3188行变成了65行。
在这里插入图片描述

.c文件开头定义了一个整形变量sleepsecs,但是赋值为2.5。在看汇编:

在这里插入图片描述这段信息表示与全局变量sleepsecs有关的信息:

  1. 此变量来自hello.c
  2. 这是一个全局变量
  3. 它位于.data段
  4. 它的类型是object
  5. 它所占空间大小为4个字节
    在此之后,还有一个sleepsecs,存于rodata。这个用于秒速偏移量,表示sleepsecs在寄存器中的位置。
    在这里插入图片描述
    之后进入主函数。主函数中有局部变量i和argc,编译器会将局部变量存储在寄存器或栈中,hello.s如下:
    Argc:

argci:
在这里插入图片描述
对于程序中的立即数,会直接写到汇编程序中。
字符串:
在这里插入图片描述
这两个字符串被存储在rodate中,只读不能更改。
3.3.2 赋值:
对于变量的赋值:

在这里插入图片描述直接使用movl语句。

3.3.3 类型转换:
对于变量sleepsecs的类型转换,在编译过程中对此变量了做了隐式类型转换,直接将其作为整数存储。
3.3.4 算数操作:
Hello.c中的算数操作只有循环计数变量不停+1,在汇编代码中:
在这里插入图片描述
每次往存i的栈的对应位置加1更新。
3.3.5 关系运算的处理
对关系的判断同样出现在循环中,用于判断循环是否应该结束。
在这里插入图片描述
这里判断argc是否等于3.

在这里插入图片描述这里判断i是否小于10,进而判断循环执行位置。
3.3.6 对数组(指针)的操作
程序中的数组是main的参数argv,存放char指针。
在这里插入图片描述
在hello.s中,使用两次%rax取出这个值。在访问数组元素时,按照起始地址加偏移量的方式取出数据。
3.3.7 对控制转移的处理
跳转的全部语句如下图:

Hello.c中有两处控制转移:
在这里插入图片描述
第一处如上图,这是对if条件内容的判断,如果等于3就跳转到.L2

在这里插入图片描述第二处如上图,是在判断循环是否结束。如果循环变量i小于等于9(即小于10),就跳转到.L4处。
3.3.8 对函数的处理
参数存储顺序:
%rdi, %rsi, %rdx, %rcx, %r8, %r9,其余参数倒序压入栈中。
1.Main函数:
1)外部向main传递argc和argv,分别用%rdi和%rsi存储,main结束时return 0,会将%eax设置为0。
2)对内存进行操作,%rbp,%rsp记录栈信息。Main结束时,调用leave,恢复占空间,ret返回。
2. printf函数:
1)第一次printf只打印一个字符串,故将字符串首地址设置为%rdi,作为唯一参数传入。
2)第二次print有两个参数,设置rsi为argv【1】,设置rdx为argv【2】
3)调用printf的第一次需要call puts@PLT;第二次需要call printf@PLT。
3. exit函数:
1)退出函数,将返回值edi设置为1.
2)调用时需要 call exit@PLT
4. getchar函数:
1)调用:call getchar@PLT
5. sleep函数:
1)调用:call sleep@PLT.
2)将返回值edi设置为sleepsecs。
3.4 本章小结
本章介绍了在编译过程中,编译器对各种对象的操作。经过编译后,C语言变为更加通用且机器易理解的汇编代码。

(第3章2分)

第4章 汇编
4.1 汇编的概念与作用
概念与作用:汇编器(as)将.s汇编程序翻译成机器语言指令,把这些指令打包成可重定位目标程序的格式,并将结果保存在.o目标文件中,.o文件是一个二进制文件,它包含程序的指令编码。
注意:这儿的汇编是指从 .s 到 .o 即编译后的文件到生成机器语言二进制程序的过程。
4.2 在Ubuntu下汇编的命令
命令: as hello.s -o hello.o
效果如图:
在这里插入图片描述

4.3 可重定位目标elf格式
4.3.1. ELF Header:
在这里插入图片描述
Magic部分描述了hello.o的系统的字的大小和字节顺序,剩下的部分帮助链接器分析并解释目标文件的信息。
4.3.2 节头部表:
在这里插入图片描述

  1. 重定位节:
    记录.text节中需要进行重定位的信息。链接时,这些信息将被修改。下图为对一些对象的重定位声明。
    在这里插入图片描述
    4.4 Hello.o的结果解析
    机器语言包含以下几个部分:
    操作码、操作数的地址、结果的地址、下一条指令的地址(有可能有)
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述Hello.o 反汇编结果如下:
在这里插入图片描述
在这里插入图片描述
观察可知,反汇编代码与汇编代码并无太大修改,只是在每条汇编之前加入了机器码。
在这里插入图片描述
除此之外,原来的跳转语句中的标记(.L1,.L2等)全部被替换为实际地址,对函数的调用也变为地址。
4.5 本章小结
本章分析了hello.s被汇编得到hello.o的过程。之后查看了hello.o的ELF,又对hello.o进行了反汇编,并将反汇编的内容与汇编文件进行了对比,分析得出了汇编指令到机器语言的对应关系。
(第4章1分)

第5章 链接
5.1 链接的概念与作用
链接:链接是将多个文件拼接合并成一个可执行文件的过程。通过链接,分离编译可以得到实现。

5.2 在Ubuntu下链接的命令

在这里插入图片描述5.3 可执行目标文件hello的格式
在这里插入图片描述打开文件:

在这里插入图片描述可以看到节头数量增加。

在这里插入图片描述此处记录了在hello文件中各节的大小,偏移量,地址
5.4 hello的虚拟地址空间
用edb打开刚才的hello程序。

在这里插入图片描述从下图可以看出:
在这里插入图片描述
0x00400000开始,程序被载入,其中节的排布与Address中声明的相同。

在这里插入图片描述
上图为elf中的程序头表,其中记录了运行时加载的内容,同时提供动态链接的信息。每一行都提供了各个段的虚拟空间和物理内存的大小,标志位,是否对齐,读写权限的信息。
PHDR:程序头表
INTERP:需要调用的解释器(如动态链接器)
LOAD:表示需要从二进制文件映射到虚拟空间的段,其中保存了常量数据和目标代码等内容。
DYNAMIC:动态链接器使用的信息。
NOTE:辅助信息
GUN_STACK:栈是否可执行的标志。
GUN_RELRO:指定重定位之后的只读的内存区域。

5.5 链接的重定位过程分析
(以下格式自行编排,编辑时删除)
objdump -d -r hello 分析hello与hello.o的不同,说明链接的过程。
结合hello.o的重定位项目,分析hello中对其怎么重定位的。

Hello的反汇编文件与hello.o的相比多了以下内容, 经查找有关资料,补充了其功能:
.interp:ld.so的路径
.note.ABI-tag:Linux特有的段
.hash:符号的哈希表
.gnu.hash:GNU中拓展符号的哈希表
.dynsym: 运行时/动态符号表
.dynstr:存放.hynsym节中的符号名称
.gnu.version:符号版本
.gun.version_r:符号引用版本。
.rela.dyn: 运行时/动态重定位表
.rela.plt:.plt节的重定位条目
.init:程序初始化需要执行的代码
.plt:动态链接-过程链接表
.fini: 当程序正常终止时需要执行的代码
.eh_frame:异常展开和源语言的信息
.dynamic:存放被ld.so使用的动态链接信息
.got:存放程序中跟变量全局偏移量
.got.plt:存放程序中函数的偏移量
.data:初始化过的全局变量或生命过的函数。

5.6 hello的执行流程
(以下格式自行编排,编辑时删除)
使用edb执行hello,说明从加载hello到_start,到call main,以及程序终止的所有过程。请列出其调用与跳转的各个子程序名或程序地址。

程序名称 地址
Id-2.27.so!_dl_start 0x7fce 8cc38ea0
Id-2.27.so!_dl_init 0x7fce 8cc47630
Hello!_start 0x400500
Libc-2.27.so!__libc_start_main 0x7fce 8c867ab0
-libc-2.27.so!__cxa_atexit 0x7fce 8c889430
-libc-2.27.so!__libc_csu_init 0x4005c0
Hello!_init 0x400488
Libc-2.27.so!_setjmp 0x7fce 8c884c10
-libc-2.27.so!_sigsetjmp 0x7fce 8c884b70
-libc-2.27.so!_sigjmp_save 0x7fce 8c884bd0
Hello!main 0x400532
Hello!puts@plt 0x4004b0
Hello!exit@plt 0x4004e0
*hello!printf@plt -
*hello!sleep@plt -
*hello!getchar@plt -
ld-2.27.so!_dl_runtime_resolve_xsave 0x7fce 8cc4e680
-ld-2.27.so!_dl_fixup 0x7fce 8cc46df0
–ld-2.27.so!_dl_lookup_symbol_x 0x7fce 8cc420b0
libc-2.27.so!exit 0x7fce 8c889128

5.7 Hello的动态链接分析
(以下格式自行编排,编辑时删除)
分析hello程序的动态链接项目,通过edb调试,分析在dl_init前后,这些项目的内容变化。要截图标识说明。
在dl_init之前,每一条动态共享链接库中的PIC函数的调用,由于编译器无法确定函数运行时的地址,所以需要进行重定位。此时对每一条IC的调用过,目标地址都是PLT的代码逻辑,GOT存放PLT中函数调用的下一条地址。
首先我们看plt节,plt是一个数组,每个条目是个16字节的代码,每个可被执行的库函数都有自己的PLT条目,每个条目负责调用一个具体的函数。比如我们0x4004b0这个位置的函数,它代表的就是puts这个函数,这里跳转到*0x200b62(%rip)会跳转到一个GOT条目,这个条目对于的就是我们puts函数真正的地址,0x200b62的意义是这个GOT条目与下一条指令的固定距离为0x200b62.

dl_init之前的got.plt节:

Dl_init后的got.plt节:

这里GOT[2]变为0x7f169ad84750,找到这个地址,对应的是一个叫dl_runtime_resolve的函数,所有动态库函数在第一次调用时,都是通过XXX@plt -> 公共@plt -> _dl_runtime_resolve调用关系做地址解析和重定位的。

GOT[1]变为0x7f169af96170,对应一个重定位表。

5.8 本章小结
介绍了链接的概念和作用,并对可执行文件hello的格式,分配的虚拟空间,重定位过程,执行流程及动态链接过程进行了分析。
(第5章1分)

第6章 hello进程管理
6.1 进程的概念与作用
概念:进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。
作用:使得我们的程序好像是系统中当前运行的唯一程序一样,我们的程序独占系统资源。
6.2 简述壳Shell-bash的作用与处理流程
Shell:shell是用户与操作系统之间交互的窗口。Shell是一个界面,用户在shell中输入命令,shell将其翻译并交由系统执行。
处理流程:
1)用户输入命令,shell进行解析
2)shell对命令进行切分,判断命令类型,得到参数
3)如果是内置命令,直接执行
4)如果不是内置命令,fork一个子进程执行此命令。
5)子进程执行完毕,shell将控制系统或父进程对子进程进行回收。
6.3 Hello的fork进程创建过程
在终端输入./加可执行文件名,shell将会对此字符串内容进行解析。识别出这是一个可执行文件后,shell将会调用fork创建一个新的子进程,然后在这个子进程中调用execve装入要执行的程序。父进程和子进程是相互独立的,但是同时进行的。如果子进程先于父进程结束,父进程负责子进程空间的回收工作;如果晚于父进程结束,系统将负责回收孤儿进程。
6.4 Hello的execve过程
通过edb可知,程序从0x00400000开始。当execve被调用时,系统将会从0x00400000开始执行。先从可执行文件中加载内容,然后在加载运行时的对战和共享库的存储器映射区域。

6.5 Hello的进程执行
Shell接收到可执行文件的执行命令,fork一个子进程。此子进程将调用execve函数在当前进程的上下文中加载并运行刚才的可执行文件。加载器删除子进程现有的虚拟内存,并创建一块新的空间并初始化为0。然后,通过将虚拟地址空间中的页映射到可执行文件的页,代码段和数据段都会被设置为可执行文件的内容。
6.6 hello的异常与信号处理
(以下格式自行编排,编辑时删除)
hello执行过程中会出现哪几类异常,会产生哪些信号,又怎么处理的。
程序运行过程中可以按键盘,如不停乱按,包括回车,Ctrl-Z,Ctrl-C等,Ctrl-z后可以运行ps jobs pstree fg kill 等命令,请分别给出各命令及运行结截屏,说明异常与信号的处理。
1)正常停止:

在这里插入图片描述Hello进程将会被回收,ps中无hello进程。
2)SIGSTP信号(ctrl-z):

在这里插入图片描述Shell接受到ctrl-z后,向父进程发送SIGSTP信号,显示信息,进程挂起,但并未停止。查看ps,hello进程仍在列表中,通过“fg”可将其调至前台继续执行,结束时,进程仍正常回收。

在这里插入图片描述3)SIGINT信号(ctrl-c):
Shell收到ctrl-c后,将向父进程发送SIGINT信号,父进程将会将子进程结束并回收,如图:

在这里插入图片描述4)其他信号:
中途乱按,屏幕将显示乱按的内容。如果这个内容是内置命令,shell将会解析,并在进程结束后执行;如果不是则显示错误信息。
Pstree:
在这里插入图片描述
Jobs:
在这里插入图片描述

在这里插入图片描述6.7本章小结
本章介绍了进程的概念和作用,介绍了shell的功能和工作机制,同时,通过hello的运行分析了进程的控制,信号的传递等内容。
(第6章1分)

第7章 hello的存储管理
7.1 hello的存储器地址空间
逻辑地址:访存指令给出的地址,也叫相对地址。是程序运行由CPU产生的与段相关的偏移地址的部分。
线性地址/虚拟地址:逻辑地址经过段机制后转化为线性地址,为描述符:偏移量的组合形式。分页机制中线性地址作为输入。
物理地址:程序运行时,其在内存单元中的真正地址。
7.2 Intel逻辑地址到线性地址的变换-段式管理
一个逻辑地址由两部分组成:段标识符和段内偏移量。段内偏移量是一个16位长的字段组成,称为段选择符,前13位是序列号。根据一个段描述符可以找到一个段的首地址,若干段描述符就可以组成段描述符表。再通过段标识符的前13位,直接在段描述符表中找到一个具体的段描述符,进而确定一个段。

7.3 Hello的线性地址到物理地址的变换-页式管理
虚拟内存的结构如图所示:

在这里插入图片描述虚拟内存的空间由分页机制进行管理,这个过程中,线性地址将被转化为物理地址。内核将维护hello的段的结构,即task_struct,其中mm指向某一个mm_struct,mm_struct中的pgd为本级页表的首地址,mmap在指向vm_area_struct链表,一个链表对应程序的一个段,若干链表相连hello的所有段。
系统将虚拟内存的每个段分为若干个小单位,并以此为单位将数据装入内存,这个最小的单位被称为页,一般每个页的大小为4KB。同时,物理内存中也会分为同样大小的若干个页。CPU中的MMU单元负责翻译地址,将虚拟地址根据页表中的记录翻译为物理地址。
在这里插入图片描述

在这里插入图片描述如图。虚拟地址分为VPN和VPO两部分,VPN中又分为TLBT和TLBI两部分。TLBI表示在页表中的组序号,TLBT表示标记值,如果改组中有有效位为1且标记值相同的,则命中,取出其PPN作为其物理页号。
7.4 TLB与四级页表支持下的VA到PA的变换

在这里插入图片描述
如图,CPU首先给出虚拟地址VA,VA的后12位将被MMU直接作为物理地址结果的后12位。
对于VA的前36位,也就是VPN,MMU会将其拆分为两部分:32位的TLBT和4位的TLBI,并由此去TLB中寻找相应PPN。
如果TLB中标号为TLBI的组中有标记值为TLBT的,且有效值为1的项,则查找命中(hit),直接将TLB中存储的该项的PPN输出作为PA的前40位。
在这里插入图片描述
如果TLB中没有满足条件的项,则查找未命中(miss),MMU将会去TLB的下一级存储——页表中继续查找。这时,VPN将不再被分为TLBT和TLBI,而是会被分为4个9位的VPNn(n=1,2,3,4),MMU会先根据VPN1在第一级页表中查找,得到的结果将告诉MMU内存中是否存在,及第二级页表的起始地址,之后MMU会再根据VPN2去第二级页表中查找,以此类推,直到再第四级页表中查找到PPN,MMU将其输出,与PPO组合,作为物理地址输出。
如果页表中也没有对应的PPN,则发生缺页(Page fault)。
7.5 三级Cache支持下的物理内存访问

如图,物理地址在被用来去L1级缓存中寻找内容时,将被分为三个部分:40位CT、6位CI、6位CO。

在这里插入图片描述 对于我的电脑上的cpu,L1缓存为8路64组组相连,故组索引需要6位二进制。又因为块大小为64字节,故块偏移量也为6位2进制。其余40位位标记位。
得到物理地址后,我们先使用CI找到对应的组,对组中的每一个有效值为1的块的标记值与物理地址中的CT进行匹配,如果有相同的,则查找命中(hit),按照块偏移CO取出数据。
如果没有找到符合要求的项,则发生不命中,需要向小一级存储L2继续查找。如果查询到数据,再将其写回L1。对于写回,如果L2中的数据映射在L1中的位置没有有效数据,则发生冷不命中,直接将L2的数据写入并修改有效位即可;如果对应位置有有效的数据,则发生冲突不命中,需要用L2中的数据替换L1中的数据。如果L1中的数据的脏位为1,则表示此数据已经被修改,还需要先将L1中的数据写回L2。
L2->L3同理。

在这里插入图片描述
7.6 hello进程fork时的内存映射
Shell会fork一个子进程,系统将给这个子进程分配一个唯一的PID,同时将会为这个进程分配相应的系统资源。
查找资料知,系统会将父进程和fork出的子进程的页面都标记为已读,并将两个进程的每个区域结构都标记为私有的写时复制。
7.7 hello进程execve时的内存映射
首先,系统会删除已经存在的用户区域,然后会开辟一块新的私有区域,存放.malloc,.data.,.bss,.text段。之后,在创建新的共享区域libc.so.data,libc.so.text段。最后设置PC,指向代码的入口点。
如下图所示,前边的机器码就是进程在地址段中的表示。

在这里插入图片描述7.8 缺页故障与缺页中断处理

在这里插入图片描述缺页故障:MMU无法在TLB和页表中找到虚拟地址对应的物理地址。
缺页中断处理:选择一个牺牲页面,如果这个牺牲页面被修改过,就把它交换出去,用新的页更新原来的页表。缺页处理程序返回时,CPU重新执行这条指令,得到新的VA,MMU也重新寻找物理地址。
7.9动态存储分配管理
动态内存分配起维护着堆,堆是一个进程的虚拟内存空间,一般从低地址向高地址生长。分配器会将堆中的内存视为大小不同的块,如果块中已经被进程占用,则是已分配的;没有则是空闲的。当有新的进程出现或其他进程需要新的内存空间时,分配器将会从空闲块中找到大小合适的块。
分配器分为显示分配器和隐式分配器。显式分配器要求应用显示的释放已分配的块;隐式分配器也被称为垃圾收集机制,只要检测到未使用过的块就释放这个块。
隐式空闲链表:

在这里插入图片描述对于带边界标签的隐式空闲链表分配器,一个块有一个字的头部、有效载荷、可能的一些额外的填充,结尾的一个字的脚部组成。头部负责记录这个块的大小和是否被分配的信息。如果有双字的对齐约束条件,块的大小就一定是8的倍数。这是,块大小的最低三位一定为0,我们只需要存储前29位,剩余的三位用来编码其余信息,此块是否被分配就存在最后一位。
头部后面是有效载荷,大小可以是任意的,作用是填充,大多为了满足对其要求或解决外部碎片。
一个已经组织好的,连续的已分配块和空闲块的排列成为一个隐式空闲链表。空闲块是通过其头部的大小字段隐含的连接着的。分配器在分配内存时,将遍历所有的块,找到一个大小合适的空闲块。
合并:如果只是释放,将会产生大量的内存碎片,所以合并机制是必不可少的。根据内存之间的关系,我们可以分为四种情况:前空后空、前不空后不空、前空后不空、前不空后空。通过改变头部和脚部中的值就可以完成这些操作。
7.10本章小结
本章介绍了hello的存储器的地址空间、inter的段式管理、页式管理,分析了从虚拟地址VA到物理地址PA的变换方式、从PA到cache再到内存的访问过程。还介绍了fork、execve的内存映射,缺页故障与缺页中断处理、动态存储分配管理等一系列内容。

(第7章 2分)

第8章 hello的IO管理
8.1 Linux的IO设备管理方法
(以下格式自行编排,编辑时删除)
设备的模型化:文件
Linux将所有的IO设备都视为文件,所有的输入和输出,都变成对对应文件的读或写。
设备管理:unix io接口
这种控制I/O设备的方式使得所有的输入以一种统一的方式执行,内核为设备引出的一个简单低级的应用接口,称为Unix I/O.
8.2 简述Unix IO接口及其函数

  1. 打开文件:进程向系统要求打开一个文件,系统会返回一个非负整数,此数为描述符,他在后续的鱼这个文件有关的任何操作中代表这个文件,内核记录有关于这个文件的所有信息。
    在这里插入图片描述

Open函数将文件名转换为文件描述符,并且返回描述符数字。Flags表示进程访问文件方式。
2. 改变位置:对于每个打开的文件,内核都会记录一个位置,此位置为从所有文件的开头开始计算的情况下,此文件的偏移量。
3. 读写文件:
1)读操作:从文件中复制需要读取的字节到内存中。

在这里插入图片描述 2)写操作:从内存总复制文件大小个字节到对应文件。读写操作都用到之前记录的文件位置。

在这里插入图片描述4.关闭文件:内核释放文件打开时的数据结构。

8.3 printf的实现分析
(以下格式自行编排,编辑时删除)
https://www.cnblogs.com/pianist/p/3315801.html
从vsprintf生成显示信息,到write系统函数,到陷阱-系统调用 int 0x80或syscall.
字符显示驱动子程序:从ASCII到字模库到显示vram(存储每一个点的RGB颜色信息)。
显示芯片按照刷新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点(RGB分量)。

在这里插入图片描述printf的函数体的参数的个数为不确定个, 表示第一个参数。

在这里插入图片描述vsprintf的作用就是格式化。它接受确定输出格式的格式字符串fmt。用格式字符串对个数变化的参数进行格式化,产生格式化输出。

在这里插入图片描述 Write会调用中断实现特定的系统服务。再找INT_VECTOR_SYS_CALL:

在这里插入图片描述syscall将字符串中的字节“Hello 1180300220 崔涵”从寄存器中通过总线复制到显卡的显存中,显存中存储的是字符的ASCII码。之后,字符显示驱动子程序会将ASCII码转化为点阵信息,将其存储在vram中,显示芯片会在vram中读取此信息,并向液晶显示器传输对应点的RGB值。

8.4 getchar的实现分析
异步异常-键盘中断的处理:键盘中断处理子程序。接受按键扫描码转成ascii码,保存到系统的键盘缓冲区。
用户按键时,键盘接收到该按键对应的键盘扫描码,同时产生中断请求。键盘终端服务将根据这个扫描码判断用户所按键位,并作出相应处理。处理结束后,将通知中断控制器本次终端结束并实现中断返回。
如果用户按下控制键,则在键盘标志字中设置器标志位;如果按下功能键,会根据控制键的标记位一同确定系统的扫描码,并把系统扫描码和一个‘0’存入键盘缓冲区。
getchar等调用read系统函数,通过系统调用读取按键ascii码,直到接受到回车键才返回整个字符串,之后进行封装,大体逻辑时读区字符串的第一个字符然后返回。

8.5本章小结
本章介绍了Linux的IO设备管理办法,Unix IO接口及其函数,分析了printf函数和getchar函数,了解了字符串从被键盘输入到在屏幕上显示的整个过程。
(第8章1分)
结论
Hello的一生(020):

  1. 源代码:用高级程序语言(c)写出hello的代码。(hello从0开始)
  2. 预处理:将hello.c调用的外部的库和头文件全部整合到一起成为hello.i文件
  3. 编译:将hello.i编译成为汇编文件hello.s,转变为汇编语言
  4. 汇编:将hello.s变成可重定位目标文件hello.o
  5. 链接:将hello.oy与可重定位目标文件和动态链接库俩节成为可执行目标文件hello
  6. 运行前识别命令:在shell中输入
    ./hello 1180300220 崔涵
    Shell将识别出命令内容,并向系统发送信号
  7. fork:shell将为此文件创建一个新的空白子进程
  8. 运行:shell利用execve,加载器,进入程序入口之后程序开始载入物理内存,进入函数体。
  9. 执行:CPU将其分配到某些事件片运行,在一个事件片中,程序将可以调动所有Cpu资源。
    10.访存:MMU将CPU给出的虚拟地址翻译为物理地址,再根据物理地址去内存或磁盘中寻找数据
    11.动态申请内存:通过调用malloc,从堆中申请内存。
    12.结束:进程结束时,shell父进程将会负责回收子进程的资源,内核删除此子进程的所有数据结构。(hello到0结束)
    到此为止,我们对hello的运行过程全部结束。由于现在硬件的能力不断提高,hello在本文中本分析的若干过程只是一瞬间就结束;但实际上,这个程序爷经历了系统对于所有进程都要进行的必要的所有步骤。麻雀虽小,五脏俱全,即使写了这么多,我对hello运行的全部过程还是了解的不够细致,在今后的学习中,我也会不断提高补充。
    (结论0分,缺失 -1分,根据内容酌情加分)

附件
列出所有的中间产物的文件名,并予以说明起作用。
Hello.c 源文件
Hello.i 对hello.i进行预处理后的文件
Hello.s 对hello.i 编译后得到的汇编文件
Hello.o 对hello.s进行汇编之后的可重定位文件
Hello 链接所有文件后得到的可执行文件
Asm.txt Hello.s中内容的txt文件
Elf.txt Readelf读取hello.o得到的文件

(附件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.
[7] https://blog.csdn.net/weixin_42010279/article/details/85460161
[8] https://blog.csdn.net/dxyinme/article/details/85322271
[9] https://blog.csdn.net/hahalidaxin/article/details/85144974
[10] https://www.cnblogs.com/pianist/p/3315801.html
[11] https://www.cnblogs.com/bhlsheji/p/4868964.html

(参考文献0分,缺失 -1分)

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值