怀念夏天 发表于 2024-6-20 21:14:38

哈尔滨工业大学HIT-ICS2024大作业-程序人生-Hello‘s P2P

第1章 概述

1.1 Hello简介

①P2P:这一过程是指 Hello如何从C源文件经过预处置处罚变化为可实行文件,这一过程共需经历四个阶段:
1)预处置处罚器处置处罚,天生文本文件hello.i
2)编译器处置处罚,天生汇编程序hello.s
3)汇编器处置处罚,天生文件hello.o
4)毗连器处置处罚,将其与库函数毗连,最终天生可实行文件hello(之后通过体系创建进程实行hello)
②020:这一过程是指Hello如何在程序中运行,这一过程分为三个阶段:
1)使用shell命令表明程序。Shell将通过execve函数和fork函数将hello加载到相应的上下文中,并将程序内容载入物理内存。
2)调用main函数,运行hello程序。
3)程序运行结束,父进程接纳进程,开释hello程序所占据的内存并删除相关内容。
1.2 环境与工具

①硬件环境:X64 CPU;2GHz;2G RAM;256GHD Disk 以上

②软件环境:Windows10 64位;VMware Workstation Pro15.5.1;Ubuntu 20.04.4

③开发和调试工具:gdb;edb;objdump;readelf;Code::Blocks20.03

                       

1.3 中心结果

①hello.i:hello.c预处置处罚后的文件。

②hello.s:hello.i编译后的文件。

③hello.o:hello.s汇编后的文件。

④hello:hello.o链接后的文件。

⑤hello1asm.txt:hello.o反汇编后代码。

⑥hello2asm.txt:hello反汇编后代码。

⑦hello.o_elf:hello.o用readelf -a hello.o指令天生的文件。

⑧hello_elf:hello用readelf -a hello指令天生的文件。

1.4 本章小结

     本章节是对文章后续处置处罚、展示进行背景陈述,运用术语简介了“Hello的自白”中所包罗的计算机体系运行过程,陈列了完成本实行所运用的实行环境、开发工具和中心内容说明,以便后续阅读。
(第1章0.5分)



第2章 预处置处罚

2.1 预处置处罚的概念与作用

①预处置处罚的概念:预处置处罚是指预处置处罚器在源代码编译前所进行的一系列文本操作,其重要包括删除注释、处置处罚#开头的预处置处罚指令(如#include、#define)等。
②预处置处罚的作用:
1)去除注释:同字面意义,删除源代码文件中写入的注释行
2)进行宏更换:#define所写内容即为宏,宏更换指的就是实行#define所写内容。
3)展开头文件:将#include所指定的头文件写入并展开。
4)做条件编译:重要与#if系列语句有关,可以在不同条件下实行不同的程序。
2.2在Ubuntu下预处置处罚的命令

命令行:gcc hello.c -E -o hello.i
https://img-blog.csdnimg.cn/direct/0b130124065c4f05b369f7f146250dae.png
2.3 Hello的预处置处罚结果剖析

https://img-blog.csdnimg.cn/direct/1f3d8575e97046e8b87190cc47f33bc4.png







Hello.i在ubuntu中可作为文本文件直接打开,可见总共3061行,而3048行起后续与源代码中main函数内容同等,往前翻阅可发现注释已经全部被删除,而#所写已经展开。
2.4 本章小结

本章是hello“程序生”的起点,从最起始的预处置处罚开始,解说了预处置处罚的概念和作用,展示了ubuntu下预处置处罚操作及操作结果,并对预处置处罚文件hello.i进行了剖析,直观反应预处置处罚的作用。
(第2章0.5分)

第3章 编译

3.1 编译的概念与作用

①编译的概念:
编译是教唆用编译程序,从源代码产生目标程序的过程。
编译也可以说是从高级程序计划语言转换到机器能明白的汇编语言的过程。
②编译的作用:
1)产生目标程序,得到汇编语言文件
2)编译器本身也具有一些功能,好比语法检查等等       
3.2 在Ubuntu下编译的命令

   命令行:gcc hello.i -S -o hello.s
https://img-blog.csdnimg.cn/direct/689407b876894cf18bd45cd877eadbf7.png







3.3 Hello的编译结果剖析

3.3.1记载文件信息:
https://img-blog.csdnimg.cn/direct/56f49e9aa1c74f6c98a5d25cc65c2249.png①源文件.file
②代码段.text
③只读代码段.section  &  .rodata
④字节对齐方式.align(此处为.align 8即是八字节对齐方式)
⑤字符串.string
⑥全局变量.global
⑦main函数类型.type
3.3.2操作局部变量:
https://img-blog.csdnimg.cn/direct/375235368cbb41db8007bce94d839c0d.png①当进入main函数时,将根据局部变量的需求,为原本存储在栈中的局部变量申请一段栈上的空间以供使用,这部门空间将在局部变量的生命周期结束后予以开释。
②在hello.c中设定的局部变量即为i,而在hello.s中可以看到,其跳转到了L3的位置后又将栈指针减少4,表明存储了局部变量i。
③跳转到L4,进行下一步操作
3.3.3操作字符串常量
https://img-blog.csdnimg.cn/direct/ab753b804dc146848151095164c80849.png
①在进入main函数前,.rodata处已经存储了字符串常量,并标志该位置是只读的。
②在main函数中使用字符串时,将只能得到该字符串的首地点
3.3.4操作立刻数:
https://img-blog.csdnimg.cn/direct/67e216ba088649d78975d736b08e07cf.png
立刻数直接用$+数字的方式表现。
3.3.5通报参数argv:
https://img-blog.csdnimg.cn/direct/1ddfd656d1f048c78ca4b0526bad44ef.png
①进入main函数后,先将%rbp压栈保存起来,以便后续使用
②将栈指针减少32位,由此将%rsi和%rdi所存的值存进栈中。可见,%rbp-20和%rbp-32的位置分别存储了argv数组和argc的值
3.3.6操作数值:
https://img-blog.csdnimg.cn/direct/17f68becd4c045f9bfadcc8c5c36ea2a.png
想要操作数组,一般而言都只必要找到数组首地点之后增长偏移量即可。
①%rbp-32即为数组首地点,每次调用时将其传给%rax,再增长偏移量即调用乐成,此中16、8的偏移量分别对应了argv与argv
②调用printf之后又进行了类似的操作,本次偏移量为32,对应于argv,将其存入%rdi中供后续使用。
3.3.7函数的调用及返回
https://img-blog.csdnimg.cn/direct/a97be1ca9c3841ada6b360cfda525e68.png
①寄存器传参函数的前六个参数,其返回值存储于%rax寄存器。
②调用函数时,需先将相应的值存入相应的寄存器,然后再使用指令进行操作:call-调用函数,ret-返回函数
3.3.9循环操作
https://img-blog.csdnimg.cn/direct/97ca4494a0b34f839b69b0f2326a48e4.png
对于for循环,一般遵照以下操作原则:
①存储循环变量于寄存器,每次实行完循环体后,更新该循环变量
②通过cmp命令行比较循环变量,当满足条件时脱出循环,否则继续循环
3.3.10 赋值
https://img-blog.csdnimg.cn/direct/f398737eff6943529f259e76f74c789e.png
整个main函数中多次使用了赋值操作,通过movq、movl指令即可完成赋值。
3.4 本章小结

这一章首先分析了编译的概念和作用,再在ubuntu下现实进行了编译操作并展示结果,通过按类型、操作分析编译结果文件,生动体现了编译的操作方法和重要作用
(第3章2分)

第4章 汇编

4.1 汇编的概念与作用

①汇编的概念:
汇编是指把汇编语言编写的程序转换为相匹配的机器语言程序的过程。
汇编程序所输入的是用汇编语言编写的源程序,而输出的是用机器语言编写的目标程序。
②汇编的作用:
1)将程序转写为机器语言,让机器可以或许明白程序
2)汇编过程中可从汇编程序得到一个可重定位目标文件,便于后续的链接操作。

4.2 在Ubuntu下汇编的命令

命令行:gcc -c hello.s -o hello.o
https://img-blog.csdnimg.cn/direct/f62847c0b76444bc9d1cf97035f7d5d6.png4.3 可重定位目标elf格式

   ①命令行:readelf -a hello.o  > hello.elf
   ②elf内容展示:
https://img-blog.csdnimg.cn/direct/6fdd3cf1da5b4a65b9371b4abaeda2f2.pnghttps://img-blog.csdnimg.cn/direct/4a6c0b48a1c0419e98d0f23e1bb759c5.png
③elf内容剖析:
1)段头表/程序头表:包罗页面巨细,虚拟地点内存段(节),段巨细
2).text 节:已编译程序的机器代码内容
3).rodata 节:用于表明只读数据,如printf的格式串、跳转表等
4).data 节:用于表现已初始化的全局和静态变量
5).bss 节:用于表现未初始化或者初始化为0的全局和静态变量。这一节仅有节头,节的本身并不占用磁盘空间
6).symtab 节(符号表):内含函数和全局/静态变量名,节名称和位置
7).rel.text 节(可重定位代码):指.text 节的可重定位信息,在可实行文件中必要修改的指令地点,需修改的指令等
8).rel.data 节(可重定位数据):指data 节的可重定位信息,在合并后的可实行文件中必要修改的指针,数据的地点等
9).debug 节(调试符号表):内容为符号调试的信息
10)节头表:内含每个节的在文件中的偏移量、巨细等
4.4 Hello.o的结果剖析

①命令行:objdump -d -r hello.o 
②结果展示:
https://img-blog.csdnimg.cn/direct/16d0adb8b50743f080def86b02e2a476.png③结果剖析:
此中大部门结果仍然是可读的汇编代码,但也掺杂了相称部门的“机器代码”。这些机器代码是二进制机器指令的聚集,每一条机器代码都对应一条机器指令,所有汇编代码都可以通过机器二进制数据进行表现,汇编代码中的操作码和操作数通过某种影响和机器语言一一对应,由此可以让二进制机器也明白代码的含义并正确实行。此中机器代码与汇编代码的不同可扼要概括为:
1)函数调用方式不同。汇编代码中,函数的调用直接通过函数名进行;而在机器代码中,call的目标地点是当前指令的下一条地点。机器代码中,对于这种不确定地点的调用,必要在链接时才能确定其地点。
2)分支跳转方式不同。汇编代码中使用标识符来确定跳转目标;机器代码中经过转写直接使用地点实现跳转。
4.5 本章小结

这一章首先扼要说明了汇编在“程序生”中的概念与作用,随后在ubuntu中现实操作了汇编并天生重定向文件,对elf文件的内容进行了详细剖析。接着还进行了反汇编并对反汇编结果进行阐释,由此衍生,表明了机器代码与汇编代码的关系与不同。
(第4章1分)

第5章 链接

5.1 链接的概念与作用

①链接的概念:
链接是指将各种代码和数据片段整合为一个单一文件的过程,这一文件可以被加载到内存实行,由此使得程序可被实行。
②链接的作用:
1)分离编译。链接可以使程序被分为不同的小模块,更加便于管理、修改和维护
2)确定地点。使得机器代码中所调用的不确定地点可以被确定
5.2 在Ubuntu下链接的命令

命令行:ld -o hello -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/crti.o hello.o /usr/lib/x86_64-linux-gnu/libc.so /usr/lib/x86_64-linux-gnu/crtn.o
https://img-blog.csdnimg.cn/direct/93d5810da30843f8aa58c886773257c4.png可以看到天生了hello文件
                       
5.3 可实行目标文件hello的格式

①查看ELF头:
https://img-blog.csdnimg.cn/direct/beeba44e7c434376b46f33fc019c3af5.png
此中文件类型发生了变化,变为了EXEC(可实行文件)。节头部数量(Number of section headers)也发生了变化,变为了27个。
②Section头:
https://img-blog.csdnimg.cn/direct/358fc577167447359103b16845a46a90.png节头部表对hello中所有信息进行了声明,包括了巨细(Size)、偏移量(Offset)、起始地点(Address)以及数据对齐方式(Align)等信息。
根据始地点和巨细,我们就可以计算节头部表中的每个节所在的区域。
③符号表:
https://img-blog.csdnimg.cn/direct/5f01f9a4816d40c982000cc281a5a86e.png可以看到经过链接符号表的符号数量急剧增长,表明经过链接后符号表中引入了很多其他库函数的符号。
④可重定位段信息:
https://img-blog.csdnimg.cn/direct/5121c70d47ee49ffb40881464cbdd809.png

5.4 hello的虚拟地点空间

①edb结果图:
https://img-blog.csdnimg.cn/direct/4d008f71807e451abb1d8de1a2b86fc9.png②.inrep段:
在readlf中可以查看到.inrep的地点为0x04002e0
https://img-blog.csdnimg.cn/direct/69ddef7dd8e2442598058cf324ea0b41.png
由此地点在edb中继续查看(goto expression):
https://img-blog.csdnimg.cn/direct/35f92c46e1034c7abb3ad12015c6fd8a.png
https://img-blog.csdnimg.cn/direct/537fbe1f523f4eb7bc99f6e412f1a1fe.png
③.text段:
在readlf中可以看到.text地点为0x4010f0
https://img-blog.csdnimg.cn/direct/16520040ea9745869a99ea3c3b2d30cd.png
Edb中查看结果为:
https://img-blog.csdnimg.cn/direct/7eb0b75aa6d748698a26ba467a3a601a.png
④.rodata段:
https://img-blog.csdnimg.cn/direct/6224e3a3118949f287071e610eb426e4.png
在readlf中可以看到.rodata段地点为0x402000
Edb中查看结果为(symbolviewers):
https://img-blog.csdnimg.cn/direct/52b9e467853947c3b985f533e88d8e13.png
5.5 链接的重定位过程分析
①反汇编结果展示:https://img-blog.csdnimg.cn/direct/d0a1eac415e34792bc3c3abf5792f85c.pnghttps://img-blog.csdnimg.cn/direct/7ac1a5be5fae406b9a18780466f130fa.pnghttps://img-blog.csdnimg.cn/direct/25a507edfb554f92b114deaa38b0fe21.png
②过程分析:
可以看出,在hello.o中跳转指令和call指令后为绝对地点,而在hello中已经是重定位之后的虚拟地点。以0x4011f6的call指令举例剖析毗连过程:
1)
https://img-blog.csdnimg.cn/direct/0508c703b34c4becbcbd5436ef5d2e4a.png
在此处,应该绑定的是第0xc(十进制12)个符号
2)
https://img-blog.csdnimg.cn/direct/4afb0d1c62dc482ba4b9d9425fb15ed5.png
打开符号表,可以找到第12个符号为puts,即此处应绑定puts的地点
3)
在前面hello反汇编结果中可见,puts地点为0x401090。而由于机器代码跳转的特殊性,PC的值为call指令的下一条地点0x4011fb。跳转目标位0x401090,中心存在0x16b的距离。
由此反推,PC必要减去0x16b,最终反映为加上0xff ff fe 95,服从小端法输入规则,重定位目标应该为95 fe ff ff。
5.6 hello的实行流程


使用edb中的symbolviewer进行查看,截图结果依次如下:

https://img-blog.csdnimg.cn/direct/7714eb4439cb494d9ad96bf49ef1aa8c.pnghttps://img-blog.csdnimg.cn/direct/4ded48b89baf4c8eb35b731dc2820059.pnghttps://img-blog.csdnimg.cn/direct/5fff4a20bcc3499d8b1751f8219084d4.pnghttps://img-blog.csdnimg.cn/direct/6f2287b24baa4f969c4e828eeed17b3f.pnghttps://img-blog.csdnimg.cn/direct/012cce6810db4f4ba09a81f3ff0f4286.png
5.7 Hello的动态链接分析

   (以下格式自行编排,编辑时删除)
分析hello程序的动态链接项目,通过edb/gdb调试,分析在动态链接前后,这些项目标内容变化。要截图标识说明。
①动态链接的概念:动态链接的概念是基于共享库建立的。在程序运行或者加载时,共享库可以加载到程序的恣意内存地点并和一个程序链接起来。相较于把所有模块链接起来成为一个单独的可实行文件的静态链接,它在运行时才成为一个完整的程序,因此称为动态链接。
②.plt与.got:
PLT是一个数组,每个条目是16字节代码。此中PLT是个特殊条目,它直接跳转动态毗连器。一般来说,被可实行程序调用的库函数都有本身的PLT条目并负责调用一个具体的函数,其存在对应关系
GOT也是一个数组,但每个条目是8字节。GOT和PLT团结使用时,GOT和GOT用于存放信息以供动态毗连器使用,而GOT是动态链接器在1d-linux.so模块中的入口点。其余每个条目与PLT条目类似,对应于一个被调用的函数。
③hello在动态毗连器加载前后的重定位存在差异,其变化如截图所示:
https://img-blog.csdnimg.cn/direct/705beb80cb1c4b1785aa15f5f8900d94.png
(加载前的.init)
https://img-blog.csdnimg.cn/direct/4f4756e791f1412988b054c66d78f1bb.png
(加载后的.init)
5.8 本章小结

这一章解说了链接相关的知识,首先阐述了链接的概念与作用,随后在ubuntu下现实操作并展示了链接结果,之后重定位分析链接过程、解读hello虚拟内存空间,并详细展示了动态链接的概念、作用和带来的影响。
(第5章1分)


第6章 hello进程管理

6.1 进程的概念与作用

①进程的概念:
进程是指一个实行中的程序的实例,体系中每个程序都运行在某个进程的上下文中,其内含多种程序正常实行所必要的状态。
②进程的作用:
进程提供给程序两个关键的假象:
1)一个独立的逻辑控制流,好像我们的程序独占地使用处置处罚器。
2)一个私有的地点空间,好像我们的程序独占地使用内存体系。
6.2 简述壳Shell-bash的作用与处置处罚流程

①Shell-bash的作用:
它是一种命令表明器,可以表明用户输入的命令并将其送入内核以供机器读取明白,代表用户运行其他程序。
②Shell-bash的处置处罚流程:
1)读/取值步骤:由读取用户的一个命令行开始,壳进行一系列的读/取值步骤至终止
2)求值步骤:剖析命令行并代表用户运行程序。在剖析命令行后eval函数将调用builtin_command函数检查其是否是内置命令:
若命令行第一个参数是一个shell内置命令名,则shell立刻实行这个命令;
若命令行第一个参数不是一个shell内置命令名,shell则以为这个参数是一个可实行目标文件的名字,这个文件将会被加载到另一个新的进程上下文中运行。
3)判断末了一个参数是否为“&”,如果则shell不会等候这个命令完成,若否则shell在前台实行该命令直至其完成
6.3 Hello的fork进程创建过程

使用fork函数:pid_t fork(void)创建子进程。所创建的子进程将得到一份与父进程拥有雷同虚拟地点空间但又与之独立的副本,从而得到雷同的代码、共享库、栈等底子信息。同时,子进程还会获得与父进程打开文件描述符雷同的副本,由此当父进程fork时,子进程可以读取父进程当中的恣意文件。
父进程与子进程拥有不同的PID,而子进程的PID总黑白零的,因此返回值是判断程序毕竟是在子进程还是父进程的重要本领。
6.4 Hello的execve过程

①使用execve函数,在当前进程的上下文中将加载并运行一个新程序
②若程序运行出现错误,则execve将返回到调用程序,若乐成则不返回
6.5 Hello的进程实行

①进程调治:在进程实行中,内核可以决定抢占当前进程,并重新开始一个先前被抢占过的进程,这种决策叫做调治,其由内核中的调治器进行。这一机制建立在上下文切换机制的底子之上。
②上下文切换机制:这一机制必要在内核模式(核心态)下进行。进程若要从用户态进入核心态,只能通过发生异常来实现。当异常发生时,体系进入和心态,内核可以实行从某个进程A到进程B的上下文切换,
在切换的第一部门,内核代表进程A在核心态下实行指令,而在某一时刻开始又代表进程B在内核模式下实行指令。切换完成后,内核代表进程B在用户态下实行指令。由此可实现多使命处置处罚。
6.6 hello的异常与信号处置处罚



类别
原因
异步/同步
返回行为
中断
来自I/O装备的信号
异步
总是返回到下一条指令
陷阱
故意的异常
同步
总是返回到下一条指令
故障
潜在可恢复的错误
同步
大概返回到当前指令
终止
不可恢复的错误
同步
不会返回
②在hello中大概发生的异常:
1)中断:在进程运行过程中出现一些I/O输入,好比敲击键盘等等,就大概触发中断。此时体系会陷入内核,调用中断处置处罚程序进行返回。
2)陷阱:其同于体系调用,它是一种故意的异常,也是实行某一条指令的结果,hello运行过程中实行sleep函数就有大概触发这种异常。
3)故障:这是由错误引起的,并且这种错误大概会被恢复。Hello实行过程中大概会存在缺页导致的故障
4)终止:不可恢复的致命错误将导致终止的出现,通常是一些硬件上的错误。
③命令结果展示:
1)运行过程中按回车:
https://img-blog.csdnimg.cn/direct/3f97b346ad384b48b8a1c2118f522f3f.png
2)输入Ctrl+c
https://img-blog.csdnimg.cn/direct/9227a7ad585b44a99a6a534a6f7693c9.png
3)输入Ctrl+z
https://img-blog.csdnimg.cn/direct/43d61dfbe1f94720bddf91af2b1173c2.png
4)输入ps:
https://img-blog.csdnimg.cn/direct/9587715f568e4b9aa2d3bcd3a1be1f33.png
其是对后台程序的监督
5)输入jobs:
https://img-blog.csdnimg.cn/direct/94f1d0ae51a34bae921709b3412911b6.png
可以看到暂停的进程
6)输入pstree:
https://img-blog.csdnimg.cn/direct/c2c0d1cb846b46389a762e62e3ea6d97.pnghttps://img-blog.csdnimg.cn/direct/40dd02e3dbf54f7ab960bf435414e305.png
以树状图的情势展示了全部进程
7)输入fg:
https://img-blog.csdnimg.cn/direct/8b69e6216af1426f909a5175e2adb125.png
停止的进程重新在前台运行
8)输入kill:
https://img-blog.csdnimg.cn/direct/7e700a72b6594b63856700871cfd9eff.png
向指定进程号发送9号信号,杀死了该进程。
6.7本章小结

这一章详细报告了程序如何从可实行文件酿成进程。首先解说了进程相关的概念和功能,在此之上又对壳Shell-bash的结构与作用进行简介,接着对hello进程的创建、实行过程梳理,并对此中大概产生的异常做详细分析。
(第6章1分)

第7章 hello的存储管理

7.1 hello的存储器地点空间

①逻辑地点:

逻辑地点是指由程序产生的与段相关的偏移地点部门。在C语言程序中,使用或操作读取指针变量的值就是其逻辑地点,它是相对于当前进程数据段的地点。一个逻辑地点由两部门组成:段标识符和段内偏移量。

②线性地点:

线性地点是逻辑地点到物理地点变更之间的中心层。程序代码会产生逻辑地点,即段中的偏移地点,加上相应段的基地点就天生了一个线性地点。

如果启用了页式管理,那么线性地点可以再变更产生物理地点。若没有启用页式管理,那么线性地点直接就是物理地点。

③虚拟地点:

虚拟内存空间的概念与逻辑地点类似,因此虚拟地点和逻辑地点现实上是一样的,它们都与现实物理内存容量无关。

④物理地点:

存储器中的每一个字节都有一个唯一的存储器地点,这个存储器地点称为物理地点,又叫现实地点或绝对地点,是地点总线上现实传输的地点。

                       

7.2 Intel逻辑地点到线性地点的变更-段式管理

①段式管理的概念:
段式管理是指将程序拆解为多个由逻辑实体组成的段进行存储,其产生与程序模块化直接相关。
②段式管理的操作:
段式管理必要通过段表来进行操作,段表中包罗了段号段名、段起点等底子信息,此外还必要主存占用区域表、主存可用区域表来辅助段式管理操作。
③段式管理的变更法则:
逻辑地点 = 段标识符+段内偏移量
这一变更将逻辑地点映射至线性地点。此中段标识符由索引号、表指示器和请求者特权级组成,而段内偏移量则是一个不变的常量,直接进入计算即可。
7.3 Hello的线性地点到物理地点的变更-页式管理

①页式管理的概念:
页式管理是指线性地点(VA)到物理地点(PA)之间的转换对虚拟地点内存空间进行分页的分页机制完成。
②页式管理的操作:
想要进行页式管理,必要在内存中增长“页表”作为索引。与段表类似,每一个进程都有本身的页表,记载着该进程中对应的一页所投影到的物理地点、是否有用等根本信息。为节省内存空间,体系往往采用多级页表的结构进行索引。
每一个页表条目是由一个有用位和一个n为地点字段组成。有用位表明虚拟页是否缓存在DRAM中,n位地点字段是物理页的起始地点或者虚拟页在磁盘的起始地点。
③页式管理的变更法则:
要将虚拟地点转换为物理地点,必要先查询页表来判断一个虚拟页是否缓存在DRAM的某个地方,如果它不在DRAM的某个地方,通过查询页表条目可以知道虚拟页在磁盘的位置。今后,页表将虚拟页映射到物理页完成变更。
7.4 TLB与四级页表支持下的VA到PA的变更

①关于多级页表:
在7.3中提到,为了节省页表所占用的内存空间,往往采用多级页表的情势进行索引。在多级页表中,一级页表中每个PTE映射虚拟存储空间中一个由很多虚拟页组成的片,假设该片中至少有一个虚拟页已经被分配,则一级页表的PTE将指向一个二级页表的基址,二级页表中每个PTE再映射一个更小的片,如此循环往复,直到第k级页表的PTE存储的是PPN。由于一级页表项为空,所以对应的二级页表就不存在而无需保存,如许一来只有一级页表必要常驻在主存中,而二级页表可以根据必要进行创建、页面调入或调出。如此便节省了用于存储页表的空间。

②翻译后备缓冲器TLB:
考虑以下两点:1.每次访问PTE都必要耗费一定的时间;2.每次最近访问的PTE和存储器层次结构中其他地方一样具有局部性,因此可以设立一个页表的缓存来加速地点翻译。
TLB(翻译后备缓冲器)是MMU中一个小的具有高相联度的聚集,其每一行都保存着一个单个PTE组成的块,最常用的PTE可以缓存在TLB中,如许就省去了每次访问PTE必要访问L1乃至内存的时间开销。
③现实变更流程:
以intel i7的VM体系为例,该体系有4级页表,36位VPN被分别成4个9位的片,每个片被用作到一个页表的偏移量。CR3寄存器包罗L1页表的物理地点,VPN1提供到L1 PTE的偏移量,这个PTE包罗L2页表的基地点,VPN2提供到L2 PTE的偏移量.
在现实访问时,首先访问TLB,若TLB里缓存了要访问的PTE则可以直接从这个PTE里拼接得到物理地点,若TLB里没有缓存要访问的PTE,则必要依次访问一到四级页表。四级页表的PTE里包罗PPN,将其与VPO拼接后即可得到物理地点。
7.5 三级Cache支持下的物理内存访问

三级Cache支持下的物理内存访问与TLB相似:
使用局部性原理,采用组相联的方式,存储一段时间内所加载的地点附近的内容。在得到物理地点后,优先从L1 cache中寻找,若没有则从L2 cache中寻找,如此依次访问L1 cache、L2 cache、L3 cache和主存,完成访问。
7.6 hello进程fork时的内存映射

①fork被shell调用时:
内核将为hello进程创建各种数据结构,分配给它唯一的PID。同时为了给hello进程创建虚拟内存,它还将创建hello进程的mm_struct 、区域结构和页表的原样副本。
与此同时,它还将两个进程中的每个页面都标志为只读,并将两个进程中的每个区域结构都标志为私有的写时复制。
②fork从hello中返回时:
hello进程此时的虚拟内存将与调用fork 时存在的虚拟内存雷同。
而当这两个进程中的任一个进程之后进行写操作时,写时复制机制就会创建新页面,由此为每个进程保持了私有地点空间的抽象概念。
7.7 hello进程execve时的内存映射

①删除已存在的用户区域。这一删除操作包括了所有虚拟地点中的用户部门已存在的区域结构。
②映射私有区域。Execve将为新程序的代码、数据等创建新的区域结构,execve此时所创建的所有新区域都是私有且写时复制的,即是其私有区域。
③映射共享区域。hello 程序与共享对象 libc.so 链接,而libc.so 是动态链接到这个程序中的,然后再映射到用户虚拟地点空间中的共享区域内。
④设置程序计数器PC。这是execve所进行的末了一个步骤,设置计数器并使之指向代码区域的入口点。
7.8 缺页故障与缺页中断处置处罚

①缺页故障的概念:
常说的“缺页”其实指的就是DRAM缓存未命中。当指令中取出一个虚拟地点时,若我们发现对该页的内存访问是正当的,但其对应的有用位却为0,则表明该页没有能正常保存在主存当中,即发生了缺页故障。
②缺页中断处置处罚:
当发生缺页故障时,进程将暂停。此时内核会选择某一个主存中的某一个页面进行牺牲,若该牺牲页面是其他进程或者这个进程本身的页表项,则将这个页表对应的有用位改为0,同时把所缺的页存入主存中的一个位置,并在该页表项将其对应的有用位置为1。在这之后重启进程实行该条语句,此时MMU就可以正常翻译这个虚拟地点了。缺页故障由此得到办理。
7.9动态存储分配管理

①动态存储分配管理的概念:
动态存储分配管理是指在程序运行时可以使用动态内存分配器,这些分配器将堆视为一组不同巨细的块(blocks)的聚集来维护每个块的分配与空闲状态。
②堆:
由动态存储分配管理器维护着的进程虚拟内存区域称为堆。当内存中的碎片和垃圾被接纳之后,内存中就会产生多余的空闲空间。为了制止内存空间的浪费,必要记载这些空闲块,而采用隐式空闲链表和显式空闲链表的方法则可以实现这一操作。
③隐式空闲链表:
当隐式空闲链表工作时,若分配块比空闲块小,则还可以把空闲块分为两部门,一部门用来承装分配块从而制止大概导致的浪费。
隐式链表采用界限标志的方法进行双向合并。即脚部与头部是均为 4 个字节,这一部门用来存储块的巨细并表明这个块的空闲与分配状态。同时定位头部和尾部,可以以常数时间来进行块的合并。由此,无论是与下一块还是与上一块合并,都可以通过他们的头部或尾部得知块巨细,从而定位整个块,制止了从头遍历链表导致的时间花销极高。
④显式空闲链表:
与隐式空闲链表不同,显式空闲链表只记载空闲块而不记载所有块。
显示空闲链表的思绪是维护多个空闲链表,每个链表中的块有大抵相称的巨细,分配器维护着一个空闲链表数组,每个巨细类一个空闲链表。当必要分配块时,只必要在对应的空闲链表中搜刮即可。
7.10本章小结

这一章聚焦于hello程序在计算机体系当中的存储与管理题目,并引出计算机体系当中的一个重要概念“虚拟内存”。在本章当中,我们详细报告了hello的四种地点及其寻找、变更、翻译的过程,阐释了TLB相关概念和流程,多(三)级缓存、动态内存管理的要点重点。
(第7章 2分)

第8章 hello的IO管理

8.1 Linux的IO装备管理方法

装备的模子化:文件
装备管理:unix io接口
所有的I/O装备都会被模子化为文件,而所有的输入和输出都被当做对相应文件的读和写来实行,这种将装备映射为文件的方式,允许Linux内核引出一个简单低级的应用接口,称为Unix I/O。这就是Linux的I/O装备管理方法。
8.2 简述Unix IO接口及其函数

①Unix I/O接口:
1)一个程序想要声明其欲访问I/O装备,只必要通过内核打开相应的文件即可。内核将返回一个非常小的非负整数,称之为“标识符”,通过它对后续此文件的所有操作进行标识。内核必要记载有关该文件的所有信息,而这个程序只必要记忆这一标识符即可。
2)Linux Shell创建的每个进程都有三个打开的文件:标准输入、标准输出、标准错误。
3)改变文件位置。每个已经打开的文件,内核中都保持着一个对应的文件位 置k。k初始为 0,而这个文件位置则是从文件开头起始计的字节偏移量,程序可以或许通过实行指令seek显式地将改变当前文件位置k。
4)读写文件。
读操作:一个读操作就是从文件复制一定数量个字节到内存。好比若要复制n个字节到内存,则从当前文件位置 k 开始,然后将 k 增长到 k + n。若给定一个巨细为 m 字节的文件,当 k >= m 即起始位置超出文件巨细时,实行读操作就会触发 EOF。
写操作:类似地,写操作就是从内存中复制一定数量个字节到一个文件,好比若要从内存写n个字节,则从当前文件位置 k开始,然后更新k直至k+n即可。
②函数
1)Open函数:int open(char *filename,int flags,mode_t node);
将filename转换为一个文件描述符,并且返回描述符数字。返回的描述符总是在进程中当前没有打开的最小描述符。flags 参数指明了进程计划如何访问这个文件,mode参数指定了新文件的访问权限位。
2)close函数:int close(int fd);
其功能是关闭一个打开的文件,若选取对象是已关闭的文件则描述符会出错。
3)read函数:ssize_t read(int fd,void *buf,size_t n);
从描述符为fd的当前文件位置赋值最多n个字节到内存位置buf。
当返回值为0时,即为触发了EOF。
4)write函数:ssize_t write(int fd,const void *buf,size_t n);
从内存位置buf复制至多n个字节到描述符fd的当前文件位置。
5)lseek函数:off_t lseek(int fd, off_t offset, int whence);
这一函数使程序显式地改变文件的当前位置
6)stat函数:int stat(const char *filename,struct stat *buf);
以文件名作为输入,并填入一个stat数据结构的各个成员。
8.3 printf的实现分析


https://www.cnblogs.com/pianist/p/3315801.html
①printf的函数体:
int printf(const char *fmt, ...)
{
      int i;
      char buf;
      va_list arg = (va_list)((char*)(&fmt) + 4);
      i = vsprintf(buf, fmt, arg);
      write(buf, i);
    return i;
}
②vsprintf的函数体:
int vsprintf(char *buf, const char *fmt, va_list args) {
    char* p;
    char tmp;
    va_list p_next_arg = args;
    for (p=buf;*fmt;fmt++) {
        if (*fmt != '%') {
            *p++ = *fmt;
            continue;
        }
        fmt++;
        switch (*fmt) {
        case 'x':
            itoa(tmp, *((int*)p_next_arg));
            strcpy(p, tmp);
            p_next_arg += 4;
            p += strlen(tmp);
            break;
        case 's':
            break;
        default:
            break;
        }
    }
return (p - buf);
}
③实现分析:
printf程序按照格式fmt结合参数args天生格式化之后的字符串,并返回该字串的长度。Printf中调用了两个外部函数,分别为vsprintf和write。
而vsprintf函数作用是接受确定输出格式的格式字符串fmt。用格式字符串对个数变化的参数进行格式化,产生格式化输出。write函数的作用则是将buf中的i个元素写到终端。
从vsprintf天生显示信息,到write体系函数,到陷阱-体系调用 int 0x80或syscall等.字符显示驱动子程序:从ASCII到字模库到显示vram。显示芯片按照革新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点。由此实现printf。
8.4 getchar的实现分析

①getchar函数体:
int getchar(void)
{
      static char buf;//缓冲区
      static char* bb=buf;//指向缓冲区的第一个位置的指针
      static int n=0;//静态变量记载个数
      if(n==0)
      {
             n=read(0,buf,BUFSIZ);
             bb=buf;//并且指向它
      }
      return(--n>=0)?(unsigned char)*bb++:EOF;
}
②实现分析:getchar函数中还调用了read函数,通过体系调用read读取存储在键盘缓冲区的ASCII码,直到读到回车符才返回。
必要注意的是,read函数每次会把所有的内容读进缓冲区,如果缓冲区本来非空,则不会调用read函数,而是直接返回缓冲区中最前面的元素。
③异步异常-键盘中断的处置处罚::键盘中断处置处罚子程序。接受按键扫描码转成ascii码,保存到体系的键盘缓冲区。

8.5本章小结

本章就是整篇文章的末了一章,也是我们hello“程序生”的句号。这一章我们批评了程序的最外层-(读写)I/O装备的有关概念,并对分别代表读写的getchar和printf函数的实现进行了分析。
(第8章1分)
结论

源代码是一切程序的开端,对于hello来说一样如此。它的生命,抽芽于新建Empty file,铸就于C语言的每一字节,并在“另保存为hello.c”时初具雏形,只待抽芽破土,“一如数万年前的初夜”。
当预处置处罚器与它相见,hello的“程序生”便由此蓬勃生长一发不可摒挡。预处置处罚器为它展开了头文件做了宏更换,深知万丈高楼起于平地的道理;接着又受编译器和汇编器做媒,让它转写成机器语言足以和刻板冰冷的计算机纹枰论道。最终经过链接,它们真正地合而为一,得到了可实行文件hello。
为了实行好它们共力而育的果实,还须得做千百般努力。通过shell剖析命令行输入的命令,然后调用fork创建子进程,再用execve映射到虚拟内存中,让hello也有容身之处。当CPU实行到hello时,读取虚拟内存地点、借缺页异常之手将hello载入主存中,让hello有了施展手脚的天地。使用多级页表、层层缓存,hello终于是被加载到了处置处罚器内部。万事俱备,只欠“输出”。
最终,在I/O装备的帮助下,结果输出到终端,它也向着世界发出了最原初又最深远的召唤:hello,world!
Hello这一程序是我们每个C语言程序员入门所实践的第一个程序,其简单短小不问可知。然人不可貌相,程序也不可器量,在hello这么浅近的小程序背后,也同样蕴含着庞大的计算机体系知识。正所谓万变不离其宗,器重每一个程序的每一处细节,才能在更大的尺度上做出更恢弘的伟业。千里之行始于足下,与君共勉!
(结论0分,缺失 -1分,根据内容酌情加分)

附件

列出所有的中心产物的文件名,并予以说明起作用。
①hello.i:hello.c预处置处罚后的文件。

②hello.s:hello.i编译后的文件。

③hello.o:hello.s汇编后的文件。

④hello:hello.o链接后的文件。

⑤hello1asm.txt:hello.o反汇编后代码。

⑥hello2asm.txt:hello反汇编后代码。

⑦hello.o_elf:hello.o用readelf -a hello.o指令天生的文件。

⑧hello_elf:hello用readelf -a hello指令天生的文件。


(附件0分,缺失 -1分)

参考文献

为完成本次大作业你翻阅的书籍与网站等
  https://www.cnblogs.com/pianist/p/3315801.html
编译和链接的过程_douguailove的博客-CSDN博客_编译过程,编译和链接的过程_编译链接-CSDN博客。

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


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 哈尔滨工业大学HIT-ICS2024大作业-程序人生-Hello‘s P2P