ics大作业

计算机系统

大作业

题 目 程序人生-Hello’s P2P
专 业 计算学部
学   号 7203610802
班   级 2036013
学 生 杨佩祺    
指 导 教 师 刘宏伟

计算机科学与技术学院
2021年5月

第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 -
结论 - 13 -
附件 - 14 -
参考文献 - 15 -

摘要

Hello的一生:从hello.c的编写完成出发,追踪hello.c如何一步步经过各种步骤程序变为一个可执行程序又是怎样一步步销毁的过程。
关键词:hello;程序;预处理;编译;汇编;反汇编;链接;计算机系统;p2p


提示:以下是本篇文章正文内容,下面案例可供参考

第1章 概述
1.1 Hello简介
P2P:P2P是form program to process的简写。在此处代表了hello.c文件由可执行程序(progress)变为进程(process)的过程。首先hello.c的诞生是由操作者在各种各样的环境(例如codeblocks等)下手敲出来的。之后通过预处理器(cpp)进行宏替换和宏展开,得到hello.i文件。之后由编译器(ccl)编译得到hello.s文件。然后通过汇编器(as)汇编为hello.o可重定位目标文件。接着又通过链接器(ld)生成可执行目标程序hello。最后在bash中输入./hello,bash会调用OS中的fork函数创建一个新的进程,然后再子进程中调用execve函数执行hello文件,这样hello便变成了一个进程(process)。
020:020是指from 0 to 0,是一个从无到有又到无的过程,开始时,并无hello文件的相关内容,通过p2p的步骤后执行文件,程序运行结束后被回收。
1.2 环境与工具
硬件环境:
lntel® Core™i7-10750H CPU @2.60GHz
NVIDIAGeForce RTX 2060
软件环境:
Windows10 & Ubuntu 20.04 64位
开发工具:
Codeblocks 64位 gcc edb
1.3 中间结果
Hello.c:c语言源程序
Hello.i:预处理文本文件,由hello.c预处理生成
Hello.s:汇编代码文件,由hello.i编译生成
Hello.o:可重定位目标文件,由hello.s汇编生成
Hello:可执行目标文件,由hell.o链接生成
Hello.asm:汇编代码文件,由hello.o反汇编生成
Hello.elf:elf格式信息,由readelf读取hello.o生成
1.4 本章小结
本章根据Hello的自白,利用计算机系统的术语,简述了Hello的P2P,020的整个过程,列出了为编写本论文,折腾Hello的整个过程中,使用的软硬件环境、开发与调试工具以及生成的中间结果文件的名字,文件的作用等。

(第1章0.5分)

第2章 预处理
2.1 预处理的概念与作用
概念:预处理器根据#开头的命令,修改原始的c程序,将所有引用的库展开为一个完整的文本文件。
作用:将宏定义替换为文本文件、处理条件编译、加载头文件和处理特殊符号。
2.2在Ubuntu下预处理的命令

应截图,展示预处理过程!

2.3 Hello的预处理结果解析
新出现的hello.i文件大小是原来的N倍,几行的代码变成几千行。

由图可知在对源程序预处理时,主函数部分保持不变。

宏被展开,头文件包含的内容也写进了文件中。
2.4 本章小结
本章主要讲述预处理的概念和作用,并对hello.c文件进行预处理然后解析了hello.i文件。

(第2章0.5分)

第3章 编译
3.1 编译的概念与作用
概念:编译器(ccl)将高级程序设计语言通过词法分析和语法分析,将合法指令翻译成汇编语言的过程。
作用:将人能读懂机器读不懂的高级程序设计语言翻译成机器能够识别的语言。
注意:这儿的编译是指从 .i 到 .s 即预处理后的文件到生成汇编语言程序

3.2 在Ubuntu下编译的命令

3.3 Hello的编译结果解析
3.3.1 汇编指令

.file:声明源文件
.text:代码街
.rodata:只读代码段
.align:对齐方式
.string:声明字符串
.global:声明全局变量
.type:声明符号是数据类型还是函数类型
3.3.2 数据类型
立即数:显式使用的一类数据,例如
寄存器变量:例如
字符串:
LC0中的数据由于是中文字符,没有对应的ASCII码,故无法直接显示。
3.3.3 赋值

Mov指令赋值,movl为4个字节movq为8个字节
3.3.4 运算

Sub为减法,add为加法
3.3.5 关系运算

Cmp比较4和%rbq-20位置比较,如果相等(je)则跳转到L2
3.3.6 if函数

比较4和%rbq-20位置比较,如果相等(je)则跳转到L2

L2会跳转到L3,L3即为if后面的代码。
若不等于4,则输出字符串后将%edi的值赋为1,控制传递 call exit@PLT
即为exit函数,此部分对应源文件中的

3.3.7 for循环

I++操作:
比较7和%rbp中的值
若小于等于则跳转到L4
若大于则 getchar
此处对应源程序中的
3.3.8 数组

Main函数的第二个参数为数组,L4中可以看到他的起始地址等。
3.4 本章小结
本章讲述了编译的概念与作用,以及ubuntu下的汇编命令和说明编译器是怎么处理C语言的各个数据类型以及各类操作的
(第3章2分)

第4章 汇编
4.1 汇编的概念与作用
概念:汇编器(as)将汇编语言翻译成机器语言,并打包成可重定位目标程序的格式的过程。
作用:将汇编语言转化为计算机能够执行的二进制代码
注意:这儿的汇编是指从 .s 到 .o 即编译后的文件到生成机器语言二进制程序的过程。
4.2 在Ubuntu下汇编的命令

4.3 可重定位目标elf格式
分析hello.o的ELF格式,用readelf等列出其各节的基本信息,特别是重定位项目分析。
使用 readelf -a hello.o打开elf

Elf头:
Magic描述了生成该系统的字的大小和字节顺序,magic为16字节的序列
余下部分包括了帮助链接器语法分析和解释目标文件信息。包括了ElF头大小、目标文件类型、机器类型、字节头部表的文件偏移以及节头部表中条目的大小和数量等信息。

节头:
节头部表包含了文件中出现的各个节的语意,包括节的类型、位置和大小等信息。由于是可重定位目标文件,所以每个节都从0开始,用于重新定位。在文件头中得到节头表的信息,然后再使用节头表中的字节偏移信息得到各节在文件中的起始位置,以及各节所占空间的大小,同时可以观察到,代码是可执行的,但是不能写;数据段和只读数据段都不可执行,而且只读数据段也不可写。

重定位节:
包含了节中需要重新定位的信息,链接器把目标文件和其他文件组合时,会修改这些位置。

符号表:
存放了程序中定义和引用函数以及全局变量的信息。

4.4 Hello.o的结果解析
objdump -d -r hello.o 分析hello.o的反汇编,并请与第3章的 hello.s进行对照分析。

反汇编代码中的操作数为十六进制,而汇编代码中为十进制。
汇编语言中的mov、sup等指令后会跟一个表示大小的字母,而反汇编指令中则没有。
汇编语言中的跳转语句后为L2、L3等代码段的名称,而反汇编代码中则为相对偏移的地址。
汇编语言中call调用直接对函数名进行调用,而反汇编语言中函数名部分为一个十六进制数。
4.5 本章小结
本章介绍了汇编的概念和作用,对hello.o的分析以及说明机器语言的构成,与汇编语言的映射关系。
(第4章1分)

第5章 链接
5.1 链接的概念与作用
概念:链接是将代码段和数据片段收集并合成一个单一且可被加载到内存执行的文件。
作用:链接可将代码段和数据段合成,因此可以对合成之前的代码段分别独立的进行操作,使得原来庞大的代码段可分块处理,提高工作的效率。
注意:这儿的链接是指从 hello.o 到hello生成过程。
5.2 在Ubuntu下链接的命令

使用ld的链接命令,应截图,展示汇编过程! 注意不只连接hello.o文件
5.3 可执行目标文件hello的格式

Magic为16字节序列
类型为可执行文件
与hello.o的ELF格式信息相比多了链接信息。
分析hello的ELF格式,用readelf等列出其各段的基本信息,包括各段的起始地址,大小等信息。
5.4 hello的虚拟地址空间

可以看出hello的虚拟地址空间开始于0x400000,结束于0x400ff0

Dynsym所在位置

Dynamic scction所在位置

节头所在位置

Rodata所在位置
使用edb加载hello,查看本进程的虚拟地址空间各段信息,并与5.3对照分析说明。
5.5 链接的重定位过程分析

在hello.o中call、jmp后跟的都是相对地址、而在hello中,由于链接器完成了重新定位的过程,于是跟的是确定的虚拟地址。

Hello中新增加了一些原本在hello.o中没有定义但直接引用的函数例如printf等。这些函数在共享库中,链接器完成了符号的解析与重新定位。
定位过程:链接器通过符号表和节头得知.data与.text在每个文件中的偏移和大小后,进行合并,然后为新的合并出来的数据和代码节分配内存,并映射虚拟内存地址。最后修改对各种符号的引用,完成重定位。
5.6 hello的执行流程
使用edb执行hello,说明从加载hello到_start,到call main,以及程序终止的所有过程。请列出其调用与跳转的各个子程序名或程序地址。
程序名称 地址
Hello!_start 0x403ff0
_init 0x4011c0
__libc_start_main 0x403ff0
puts@plt 0x401090
exit@plt 0x4010d0
printf@plt 0x4010a0
sleep@plt 0x4010e0
getchar@plt 0x4010b0

5.7 Hello的动态链接分析
分析hello程序的动态链接项目,通过edb调试,分析在dl_init前后,这些项目的内容变化。要截图标识说明。
Got.plt的地址为

调用dl_init后

0x404008开始的16字节发生变化
5.8 本章小结
本章讲述了链接的概念与作用,hello的ELF执行格式以及虚拟地址空间、链接的重定位过程分析以及执行流程和动态链接分析。
(第5章1分)

第6章 hello进程管理
6.1 进程的概念与作用
概念:进程的经典定义就是一个执行中的程序的实例。狭义上来说进程指的是运行中的程序。
广义上来说进程是指具有一定独立功能的程序关于某个数据集合的一次活动。
作用:进程给应用程序提供的关键抽象有两种:一个独立的逻辑控制流,提供一个假象,程序独占地使用处理器;一个私有的地址空间,提供一个假象,程序在独占地使用系统内存。
6.2 简述壳Shell-bash的作用与处理流程
作用:shell是系统跟计算机硬件交互时使用的中间介质,它只是系统的一个工具。用户直接面对的不是计算机硬件而是shell,用户把指令告诉shell,然后shell再传输给系统内核,接着内核再去支配计算机硬件去执行各种操作。
处理流程:
1按行读取命令
2处理引用问题
3将输入的一行字符串按照 ; 分割成多个命令。
4处理特殊字符
5变量替换
6将命令行分割成被执行命令和参数
7执行命令

6.3 Hello的fork进程创建过程
父进程通过调用fork函数创建一个新的、处于运行状态的子进程。子进程返回0,父进程返回子进程的PID 新创建的子进程几乎但不完全与父进程相同;子进程得到与父进程虚拟地址空间相同的(但是独立的) 一份副本。子进程获得与父进程任何打开文件描述符相同的副本。子进程有不同于父进程的PID fork函数被调用一次,却返回两次!

6.4 Hello的execve过程
(以下格式自行编排,编辑时删除)
Execve函数会在当前程序的上下文中加载并且运行一个新的程序。只有当读取文件出现错误时才会返回。调用fork创建子进程后,会在子进程中使用argv[]和全局变量environ作为execve的参数,执行用户输入的hello程序。Execve函数会删除当前子进程虚拟内存中的所有内容,之后根据参数构建新的用户和虚拟内存。
6.5 Hello的进程执行
结合进程上下文信息、进程时间片,阐述进程调度的过程,用户态与核心态转换等等。
上下文信息:指内核重新启动一个被抢占的进程所需要的状态,由通用寄存器,浮点寄存器,程序计数器,用户栈,状态寄存器,内核栈等构成。
进程时间片:进程执行它的控制流的一部分的每一时间段。
调度:内核暂停当前进程并重新开启一个新的进程的过程叫做调度。
用户态与核心态转换:为了保证系统的安全,限制了应用程序所能够访问的地址范围,被限制了访问地址范围的状态叫做用户态,而核心态访问不受限制,拥有最高权限。
6.6 hello的异常与信号处理
(以下格式自行编排,编辑时删除)
hello执行过程中会出现哪几类异常,会产生哪些信号,又怎么处理的。
程序运行过程中可以按键盘,如不停乱按,包括回车,Ctrl-Z,Ctrl-C等,Ctrl-z后可以运行ps jobs pstree fg kill 等命令,请分别给出各命令及运行结截屏,说明异常与信号的处理。
执行中会产生终端、陷阱、故障、终止等异常。
乱按:

Ctrl-c:

Ctrl-z:

Ps:

Jobs:

Pstree:

Fg:

Kill

6.7本章小结
本章讲述了进程的概念与作用,简述了shell-bash的作用和处理流程以及hello的fork和execve过程。分析了hello的执行过程和异常信号处理。
(第6章1分)

第7章 hello的存储管理
7.1 hello的存储器地址空间
(以下格式自行编排,编辑时删除)
结合hello说明逻辑地址、线性地址、虚拟地址、物理地址的概念。
逻辑地址:逻辑地址是指有程序产生的与段相关的偏移地址部分。Hello.o中数据和代码相对偏移地址就是逻辑地址。
虚拟地址:虚拟地址是Windows程序时运行在386保护模式下,这样程序访问存储器所使用的逻辑地址称为虚拟地址,与实地址模式下的分段地址类似,虚拟地址也可以写为“段:偏移量”的形式,这里的段是指段选择器。
线性地址:线性地址(Linear Address)是逻辑地址到物理地址变换之间的中间层。在分段部件中逻辑地址是段中的偏移地址,然后加上基地址就是线性地址。
物理地址:在存储器里以字节为单位存储信息,为正确地存放或取得信息,每一个字节单元给以一个唯一的存储器地址,称为物理地址(Physical Address),又叫实际地址或绝对地址。
7.2 Intel逻辑地址到线性地址的变换-段式管理
逻辑地址由段标识符与段内偏移量组成,段选择符为十六位字长的字符组成,其前十三位是索引号,也称段描述符。地址转换时,首先看段选择符T1,是0则转换的是GDT中的段,否则就是LDT中的段,然后根据相应的寄存器找到起始地址,接着通过段标识符找到对应的基地址,最后基地址加偏移。
7.3 Hello的线性地址到物理地址的变换-页式管理
物理内存在分配内存时的最小单元被称作帧,而虚拟内存中与之相对应的概念就是页。线性地址分为虚拟页号和虚拟页偏移。线性地址到物理地址的转换即根据线性地址的虚拟页号找到对应页表的地址,然后根据线性地址找到对应页的物理页号,最后物理页号加上虚拟页偏移量即为物理地址。
7.4 TLB与四级页表支持下的VA到PA的变换
在四级页表支持下,虚拟地址被分为4个VPN和一个VPO,每个VPN都是对应的页表的索引。通过每段的地址可以找到对应的PML4、PGD、PMD、PTE表,经过4层寻址后对应的PPN与VPO拼接起来即为PA下的地址。
7.5 三级Cache支持下的物理内存访问
L1 cache是8路64组相连高速缓存,每个块大小为64字节。根据cache大小和组数的要求,物理地址被分为标记位CT、组索引CS和块偏移CO。寻址时,L1中进行组索引位的匹配,若匹配成功,则可以根据标记和偏移的匹配结果判断是命中或是缺失。若是组索引匹配不成功,则进入L2中匹配,若L2匹配不成功则继续进入下一级缓存直到进入内存。
7.6 hello进程fork时的内存映射
当shell调用fork函数时,内核会给新进程创建一个除PID以外与父进程虚拟地址空间相同的(但是独立的) 一份副本。在这过程中创建了当前进程的mm_struct、区域结构和页表的原样副本。且两个进程中的每个页面都标记为只读,并将两个进程中的每个区域结构都标记为私有的写时复制,因此当fork函数在新进程中返回时,新进程现在的虚拟内存刚好和调用fork时存在的虚拟内存相同。
7.7 hello进程execve时的内存映射
(以下格式自行编排,编辑时删除)
Execve函数被调用时,会删除当前进程中用户部分已有的内容,然后映射私有区域,为新的程序代码、数据、栈区域等创建新的结构。接着映射共享区域(当前进程的动态链接),最后设置程序计数器,令其指向代码区域的入口点。
7.8 缺页故障与缺页中断处理
如果缺页故障则调用缺页处理程序,检查虚拟地址是否合法,不合法则触发段错误程序终止,否则检查是否有读写权限,若无则触发保护异常终止,若有则替换页表触发缺页故障指令。
7.9动态存储分配管理
Printf会调用malloc,请简述动态内存管理的基本方法与策略。
动态内存分配器维护着进程的一个虚拟内存区域,称为堆。分配器将堆视为一组不同大小块(blocks)的集合,每个块要么是已分配的,要么是空闲的。分配器分为显式分配器(要求应用显式地释放任何已分配的块,例如,C语言中的 malloc 和 free)和隐式分配器(应用检测到已分配块不再被程序所使用,就释放这个块,比如Java,ML和Lisp等高级语言中的垃圾收集 (garbage collection))
分配策略有以下几种重要的方式:
1. 隐式链表(malloc用的是这种分配策略):是由一个字的头部、有效载荷,以及可能的填充组成
2. 显式链表:双向空闲链表。在每个空闲块中,都包含一个前驱和后继的指针。
3. 维护多个空闲链表的分离储存
4. 带边界标记的合并:利用每块头尾的大小和空闲状态信息合并空闲块。
7.10本章小结
(以下格式自行编排,编辑时删除)
本章介绍了hello的储存器地址空间、intel逻辑地址到线性地址的变换、hello的线性地址到物理地址的变换、TLB与四级页表支持下的VA到PA、三级缓存下的物理内存访问和hello的fork和execve的内存映射。还有缺页故障与缺页中断处理和动态储存分配管理的几种方法。
(第7章 2分)

结论
用计算机系统的语言,逐条总结hello所经历的过程。
你对计算机系统的设计与实现的深切感悟,你的创新理念,如新的设计与实现方法。
过程:
1. 敲代码
2. 预处理
3. 编译
4. 汇编
5. 链接
6. 执行
7. 访问内存
8. 动态内存申请
9. 信号处理
10. 终止
11. 回收
计算机系统设计的精妙之处令人叹为观止,通过对课程的学习一步步了解到计算机系统从高层一步步到底层以及机器层面如何运行,令我受益良多。同时,通过对大作业以及实验的考察,更是让我对计算机系统产生浓厚的兴趣也为以后的学习打下坚实的理论基础。
(结论0分,缺失 -1分,根据内容酌情加分)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值