HIT-ICS2019大作业-程序人生-Hello’s P2P

计算机系统

大作业

题 目 程序人生-Hello’s P2P
专 业 数学类
学   号 1181200220
班   级 1812002
学 生 黄震宁   
指 导 教 师 史先俊

计算机科学与技术学院
2020年3月
摘 要
本文讲述如何经由预处理、编译、汇编、链接等过程实现hello进程。另外还介绍了hello的进程管理、存储管理、I/O管理。通过一些实例的分析,细致的讲述了一个简单的hello进程实现的过程,展现了计算机的底层实现。
关键词:进程;p2p;计算机系统

目 录

第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简介
p2p:From Program to Process
编程——预处理——编译——汇编——链接,形成可执行目标文件——运行fork进程——shell通过execve函数执行目标文件——通过mmap函数将源文件映射进内存——分配时间片执行逻辑控制流

020:From Zero-0 to Zero -0
p2p过程程序运行结束之后shell回收子进程,实现从0到0.
1.2 环境与工具
1.2.1 硬件环境
2GHz;
8G RAM;
256GHD Disk
1.2.2 软件环境
Windows7 64位以上;
VirtualBox/Vmware 11以上;
Ubuntu 16.04 LTS 64位/优麒麟 64位;
1.2.3 开发工具
Visual Studio 2010 64位以上;
GDB/OBJDUMP;
DDD/EDB等

1.3 中间结果
列出你为编写本论文,生成的中间结果文件的名字,文件的作用等。

hello.c:hello源文件
hello.i:hello.c预处理后的文本文件
hello.s:hello.i编译后的汇编文件
hello.o:hello.s汇编后的可重定位目标文件
hello:可执行文件

1.4 本章小结
本章主要讲述了hello的p2p与020的过程,列出了论文的实验环境与中间产生的文件。

第2章 预处理
2.1 预处理的概念与作用
(以下格式自行编排,编辑时删除)
概念:预处理器(cpp)根据以‘#’开头的命令(如#include<stdio.h>)修改原程序。
作用:拓展源代码,高效实现程序功能(如引入#include指定的头文件,拓展#define定义的宏。)。
2.2在Ubuntu下预处理的命令
命令:gcc -E hello.c -o hello.i

2.3 Hello的预处理结果解析
预处理hello.c文件后得到hello.i文件(txt文件),观察hello.i文件,发现原程序经过预处理后拓展出了非常多新的内容。

2.4 本章小结
本章对hello.c文件实行了预处理得到hello.i文件,告诉我们每个源程序在成为可执行文件之前都会经过预处理拓展出非常多新内容。
(以下格式自行编排,编辑时删除)

第3章 编译
3.1 编译的概念与作用
概念:通过编译程序以预处理文本文件生成汇编文本文件
作用:将.i文件生成.s文件,将高级语言翻译成通用性较强的汇编语言

3.2 在Ubuntu下编译的命令
命令:gcc -S hello.i -o hello.s

3.3 Hello的编译结果解析

(以下格式自行编排,编辑时删除)
3.3.1数据
常量:
String:

全局变量:无
局部变量:argc(存储在edi中)

3.3.2 赋值
将i赋值为0

3.3.3 类型转换
将字符串转换为整形
3.3.4 算数操作

累加i
3.3.5 逻辑操作

3.3.6 关系操作

判断i是否小于7

判断argc是否等于4
3.3.7 数组/结构/指针操作

对argv[]进行操作

3.3.8 控制转移

判断argc是否与4相等,满足条件则跳转L2

for循环
for(int i=0;i<=9;i++)满足条件进入L4,否则调出循环
3.3.9 函数操作

打印

读取字符串

休眠

将字符串转换为整形

清除回车

终止程序
3.4 本章小结
主要实现.i文件到.s文件的转变,并对生成的.s文件进行了分析,理解hello.s中汇编文件的作用及实现的功能。对于c语言和汇编语言的相互转换有了更加深刻的认识。

第4章 汇编
4.1 汇编的概念与作用
概念:汇编器将.s文件生成.o可重定位文件(二进制类型文件)的过程
作用:生成二进制机器语言文件,使其能够被cpu直接运行
4.2 在Ubuntu下汇编的命令
汇编命令:gcc -c hello.s -o hello.o

4.3 可重定位目标elf格式
ELF格式
ELF头
段头部表
.init
.text
.rodata
.data
.bss
.symtab
.debug
.line
.strtab
节头部表

readelf -h --file-header hello.o elf头

readelf -s --section-header hello.o 节头部表
4.4 Hello.o的结果解析

命令:objdump -d -r hello.o

操作数:hello.s中的操作数为十进制,hello.o中的操作数为十六进制
分支转移:hello.s中转移到L2、L3、L4等具体名称,hello.o转移到地址
函数调用:hello.s中调用的是函数名称,hello.o中调用的是函数地址
4.5 本章小结
本章通过汇编器将hello.s生成hello.o(可重定位)文件,实现了将汇编语言到机器语言的转化,通过比较,发现了二者在操作数、分支转移、函数调用上的区别。(可重定位文件需要连接后才能确定具体地址)

第5章 链接
5.1 链接的概念与作用
概念:通过链接器,将需要调用的外部程序文件(.o文件)与当前的.o文件组合成可执行文件的过程。
作用:使得分离编译成为可能,能够通过编译器将小程序块组合在一起构成比较庞大的程序。便于管理,易于利用,可以建立公共函数库。
5.2 在Ubuntu下链接的命令

ld链接命令: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

5.3 可执行目标文件hello的格式
命令:readelf -t --section-details hello

5.4 hello的虚拟地址空间
虚拟机中edb损坏无法查看
5.5 链接的重定位过程分析
命令:objdump -d -r hello

不同:
1、hello由于连接了库函数,比hello.o多出了很多函数的程序;
2、hello相比hello.o增加了init.节和.plt节;
3、hello相比hello.o跳转和函数调用使用虚拟内存地址;

连接过程:
1、符号解析,链接器将每个符号引用正好与一个符号定义关联起来.
2、重定位,链接器将根据重定位条目来修改需要被修改的引用
重定位:
1、重定位节和符号定义,链接器将相同类型的节合并为同一类型的聚合节
2、重定位节中的符号引用,链接器修改需要修改的引用使其运行时指向正确地址
结合hello.o的重定位项目,分析hello中对其怎么重定位的。
5.6 hello的执行流程
edb损坏,无法完成
5.7 Hello的动态链接分析
edb损坏,无法完成
5.8 本章小结
链接生成了hello可执行文件,对比分析了hello与hello.o的区别,加深了对于链接和重定位的理解,但由于edb的损坏使得几项重要实验步骤无法完成,较为失败。

第6章 hello进程管理
6.1 进程的概念与作用
概念:一个执行中程序的实例
作用:每次用户通过向shell输入一个可执行目标文件的名字,运行程序时,shell就会创建一个新的进程,然后在这个新进程的上下文中运行这个可执行目标文件。
6.2 简述壳Shell-bash的作用与处理流程
Shell-bash的作用:
对用户屏蔽内核的复杂性,保护内核以免用户误操。

通过Shell用户可以访问操作系统内核服务,shell调用了系统核心的大部分功能来执行程序、建立文件并以并行的方式协调各个程序的运行。

bash由于易用和免费,在日常工作中被广泛使用。同时,Bash也是大多数Linux系统默认的Shell脚本解释器。

Shell-bash的处理流程:
(以下格式自行编排,编辑时删除)
6.3 Hello的fork进程创建过程
父进程通过调用fork函数创建一个新的运行的子进程
例:

(子进程返回0,父进程返回子进程的PID
新创建的子进程几乎但不完全与父进程相同:
子进程得到与父进程虚拟地址空间相同的(但是独立的)一份副本(代码、数据段、堆、共享库以及用户栈)
子进程获得与父进程任何打开文件描述符相同的副本
子进程有不同于父进程的PID

fork调用一次后会返回两次)

Ps:进程结束后父进程执行回收( using wait or waitpid )
父进程收到子进程的退出状态
内核删掉僵死子进程、从系统中删除掉它的所有痕迹

6.4 Hello的execve过程
1、int execve(char *filename, char *argv[], char *envp[]):加载并运行程序

2、在当前进程中载入并运行程序: loader加载器函数

3、覆盖当前进程的代码、数据、栈
(保留:有相同的PID,继承已打开的文件描述符和信号上下文)

一次调用,0次返回
6.5 Hello的进程执行

进程上下文信息:就是内核重新启动一个被抢占的程序所需的状态,它由一些对象的值组成,这些对象包括通用目的寄存器、浮点寄存器、程序计数器、用户栈、状态寄存器、内核栈、和各种内核数据结构[3]。
进程时间片:是指一个进程和执行它的控制流的一部分的每一时间段。
内核态(Kernel Mode):运行操作系统程序
用户态(User Mode):运行用户程序

调度过程:在hello进程执行的某些时刻,内核可以决定抢占当前进程,并重新开始一个先前被抢占了的进程,这个决策就叫做调度,是由内核中称为调度器的代码处理的。在内核调度了一个新的进程运行后,它就抢占当前进程,并使用上文所述的上下文切换的机制将控制转移到新的进程。内核代表的用户执行系统调用时,可能会发生上下文切换;中断也有可能引发上下文切换。
用户态—>内核态:hello进程发生中断、异常、陷入机制(访管指令)
内核态—>用户态:设置程序状态字PSW后,hello进程重新回到应用代码时
6.6 hello的异常与信号处理
1、乱按键盘:对进程不产生任何影响,但乱按键盘后使用回车将会把当前行数据当作命令输入

2、回车:不影响进程,使其最终结束

3、Ctrl-C:结束hello进程

4.Ctrl-Z:hello进程挂起

4.1使用ps命令:列出当前系统中的进程

4.2使用jobs命令:显示当前shell下已启动的任务状态

4.3使用pstree命令:显示树状图表示进程关系

4.4使用fg命令:将进程调回前台

   4.5 使用kill命令:杀死一个或多个进程

6.7本章小结
本章简单讲述了进程的创建处理过程,简单介绍了shell、fork、exceve函数,对于进程的整体运行有了深一步的理解。通过hello程序对于一些异常与信号的处理有了初步了解。

第7章 hello的存储管理
7.1 hello的存储器地址空间

逻辑地址:即段内偏移地址。访问指令给出的地址。逻辑地址由段和偏移量组成,偏移量为从段地址到实际地址之间的距离。例如hello.o中的相对偏移地址。

线性地址:CPU在保护模式下,“段基址+段内偏移地址”叫做线性地址。如果CPU在保护模式下没有开启分页功能,则线性地址就被当做最终的物理地址来用,若开启了分页功能,则线性地址就叫虚拟地址[4]。例如hello中的虚拟内存地址。

虚拟地址:由CPU产生。程序访问存储器所使用的逻辑地址。可经由cpu翻译成物理地址。

物理地址:在CPU实模式下“段基址+段内偏移地址”就是物理地址,CPU可以使用此地址直接访问内存。在存储器里以字节为单位存储信息,每个字节都有一个唯一的物理地址。MMU能把hello的虚拟地址转化为物理地址。

7.2 Intel逻辑地址到线性地址的变换-段式管理

逻辑地址->线性地址==虚拟地址
线性地址=段基址+段内偏移地址

被选中的段描述符先被送至描述符cache,每次从描述符cache中取32位段基址,与32位段内偏移量(有效地址)相加得到线性地址
7.3 Hello的线性地址到物理地址的变换-页式管理

虚拟地址->物理地址

页表是一个页表条目 (Page Table Entry, PTE)的数组,将虚拟页地址映射到物理页地址。

地址转换[5]:
(1) 程序执行时,从PCB中取出页表始址和页表长度(4),装入页表寄存器PTR。
(2)由分页地址变换机构将逻辑地址自动分成页号和页内地址。
例:11406D=0010|110010001110B=2C8EH
页号为2,位移量为C8EH=3214D
或11406 DIV 4096=2
11406 MOD 4096=3214
(3) 将页号与页表长度进行比较(2<4),若页号大于或等于页表长度,则表示本次访问的地址已超越进程的地址空间,产生越界中断。
(4)将页表始址与页号和页表长度(页表项所占的内存空间大小,因为计算机是通过计算得到相应的位置,不能一眼看出)的乘积相加,便得到该页表项在页表中的位置。
(5)取出页描述子得到该页的物理块号。
(6) 对该页的存取控制进行检查。
(7)将物理块号送入物理地址寄存器中,再将有效地址寄存器中的页内地址直接送入物理地址寄存器的块内地址字段中,拼接得到实际的物理地址。
例:0010|110010001101B
1110|110010001101B=EC8EH=60558D
或 14*4096+3214=60558D
7.4 TLB与四级页表支持下的VA到PA的变换
Linux在v2.6.11以后,最终采用的方案是4级页表,分别是:
PGD:page Global directory(47-39), 页全局目录
PUD:Page Upper Directory(38-30),页上级目录
PMD:page middle directory(29-21),页中间目录
PTE:page table entry(20-12),页表项

TLB(Translation Lookaside Buffer):专门用于改进虚拟地址到物理地址转换速度的缓存。其访问速度非常快,和寄存器相当,比L1访问还快。

MMU使用四级页表将虚拟地址翻译成物理地址的过程:
下图为使用k级页表进行地址翻译的过程,

结合改图,我们容易得知使用四级页表时,虚拟地址将被分成四个片,VPN1将会有一个到L1 PTE(一级页表)的偏移量,这个PTE包含二级页表的基础地址,VPN2将会有一个到L2 PTE的偏移量……以此类推找到L4 PTE的偏移量——该PTE即为PPN(物理页号)。
7.5 三级Cache支持下的物理内存访问
1、CPU产生一个虚拟地址
2、MMU从TLB中取出相应的PTE
3.1、如果命中就将PTE发送给L1Cache
3.2、若不命中,就向下一级缓存中取出被请求的块,然后将新的块存储在组索引指示的组中的一个高速缓存行中。
4、跳转3

7.6 hello进程fork时的内存映射
当fork函数被当前进程调用时,内核为新进程创建各种数据结构,并分配给它一个唯一的PID。为了给这个新进程创建虚拟内存,它创建了当前进程的mm_struct、区域结构和页表的原样副本。它将两个进程中的每个页面都标记为只读,并将两个进程中的每个区域结构都标记为私有的写时复制。
当fork在hello进程中返回时,hello进程现在的虚拟内存刚好和调用fork时存在的虚拟内存相同。当这两个进程中的任一个后来进行写操作时,写时复制机制就会创建新页面,因此,也就为每个进程保持了私有地址空间的抽象概念。[3]
7.7 hello进程execve时的内存映射
exceve函数加载和执行Hello进程,需要以下几个步骤:

1.删除已存在的用户区域。

2.映射私有区域。为Hello的代码、数据、bss和栈区域创建新的区域结构,所有这些区域都是私有的、写时复制的。

3.映射共享区域。比如标准C库libc.so链接,那么这些对象都是动态链接到Hello进程的,然后再用户虚拟地址空间中的共享区域内。

4.设置程序计数器(PC)。exceve做的最后一件事就是设置当前进程的上下文中的程序计数器,使之指向代码区域的入口点。[3]
7.8 缺页故障与缺页中断处理
当没有创建一个虚拟地址到物理地址的映射,或者创建了这样的映射,但那个物理页不可写的时候,MMU将会通知CPU产生了一个缺页异常(进程线性地址空间里的页面不必常驻内存,在执行一条指令时,如果发现他要访问的页没有在内存中,即存在位为0,那么停止该指令的执行,并产生一个页不存在的异常)。

缺页异常调用内核中的缺页异常处理程序。(对应的故障处理程序可通过从外存加载该页的方法来排除故障,之后,原先引起的异常的指令就可以继续执行,而不再产生异常。

7.9动态存储分配管理
动态内存分配器维护者一个进程的虚拟内存区域,称为堆。分配器将堆视为一组不同大小的块的集合来维护,每个块要么是已分配的,要么是空闲的。
已分配的块显示的保留为供应用程序使用。
空闲块可用来分配,它将保持空闲,直到显式地被应用所分配。

一个已分配的块保持已分配状态直到其被释放,这种分配要么是应用程序显式地执行的,要么是内存分配器自身隐式执行的。

显式分配器:要求应用显式地释放任何已分配的块。
隐式分配器:应用检测到已分配块不再被程序所使用,就释放这个块。也叫做垃圾收集器。

C标准库中提供了malloc函数,系统通过调动malloc函数来从堆中分配块。通过free函数可以释放已分配块。
7.10本章小结
本章简单分类讲述了linux存储器地址空间,intel地址变换的段式管理和页式管理,学习了TLB与四级页表支持下的VA到PA的变换、三级Cache支持下的物理内存访问。分析了fork、execve函数的内存映射实现过程。介绍了缺页故障与缺页中断处理以及动态存储分配管理。

第8章 hello的IO管理
8.1 Linux的IO设备管理方法
设备的模型化:文件
设备管理:unix io接口

一个linux文件就是一个m个字节的序列:

B0 , B1 , … , Bk , … , Bm-1

所有的I/O设备(例如网络、磁盘和终端)都被模型化为文件,而所有的输入和输出都被当作对相应文件的读和写来执行。这种将设备优雅地映射为文件的方式,允许Linux 内核引出一个简单、低级的应用接口,称为Unix I/O,这使得所有的输入和输出都能以一种统一且一致的方式来执行。[3]
8.2 简述Unix IO接口及其函数
Unix IO接口:

打开文件:内核返回一个非负整数的文件描述符,通过对此文件描述符对文件进行所有操作。

Linux shell创建的每个进程开始时都有三个打开的文件:标准输入(文件描述符0)、标准输出(描述符为1),标准出错(描述符为2)。头文件<unistd.h>定义了常量STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO,他们可用来代替显式的描述符值。

改变当前的文件位置:对于每个打开的打开的文件,内核保持一个文件位置k,初始为0,这个文件位置就是是从文件开头起始的字节偏移量。应用程序通过seek操作,可显式地设置文件的当前位置为k。

读写文件:一个读操作就是从文件复制n>0个字节到内存,从当前文件位置k开始,然后将k增加到k+n。给定一个大小为m字节的文件,当k>=m时执行读操作会触发EOF条件。

关闭文件:当应用完成对文件的访问后,它就会通知内核关闭这个文件。作为响应,内核会释放文件打开时创建的数据结构,并将该描述符恢复到描述符池中。[3]

Unix IO函数:

  1. open()函数:打开一个已经存在的文件或新的文件

函数原型:int open(const char *pilename,int flags,int mode)

参数:
1、open将pilename转换为一个文件描述符,并且返回描述符数字。返回的描述符总是在进程中没有打开的最小描述符。
2、flags指明了进程打算如何访问这个文件。
——O_RONLY(只读)、O_WONLY(只写)、O_RDWR(可读可写)……
3、mode参数指定了新文件的访问权限位。
返回值:成功:返回文件描述符;失败:返回-1

  1. close()函数:用于关闭一个已经打开的的文件(所需头文件: #include <unistd.h>)

函数原型:int close(int fd)

参数:fd文件描述符

函数返回值:0成功,-1出错

  1. read()函数:从文件读取数据(所需头文件:#include <unistd.h>)
    函数原型:ssize_t read(int fd, void *buf, size_t count);

参数:fd:将要读取数据的文件描述词。buf:指缓冲区,即读取的数据会被放到这个缓冲区中去。count: 表示调用一次read操作,应该读多少数量的字符。

返回值:返回所读取的字节数;0(表示到EOF);-1(出错)。

  1. write()函数:向文件写入数据(所需头文件: #include <unistd.h>)

函数原型:ssize_t write(int fd, void *buf, size_t count);

返回值:写入文件的字节数(成功);-1(出错)

  1. lseek()函数:显式地修改当前文件的位置。
    (所需头文件:#include <unistd.h>,#include <sys/types.h>)

函数原型:off_t lseek(int fd, off_t offset,int whence);

参数:fd;文件描述符。offset:偏移量,每一个读写操作所需要移动的距离,单位是字节,可正可负(向前移,向后移)

返回值:成功:返回当前位移;失败:返回-1

8.3 printf的实现分析
https://www.cnblogs.com/pianist/p/3315801.html
从vsprintf生成显示信息,到write系统函数,到陷阱-系统调用 int 0x80或syscall.
字符显示驱动子程序:从ASCII到字模库到显示vram(存储每一个点的RGB颜色信息)。
显示芯片按照刷新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点(RGB分量)。
8.4 getchar的实现分析
异步异常-键盘中断的处理:键盘中断处理子程序。接受按键扫描码转成ascii码,保存到系统的键盘缓冲区。
getchar等调用read系统函数,通过系统调用读取按键ascii码,直到接受到回车键才返回。
8.5本章小结
本章简单介绍了linux下I/O设备的管理方法,加深了对于Unix下接口及其函数的理解,分析了printf和getchar函数的实现方法。
结论
Hello的经历:
1、通过I/O设备编写成为hello.c
2、经过预处理转变为hello.i
3、经过编译后成为hello.s
4、汇编器将其转化为可重定位文件hello.o
5、链接器将hello.o及外部函数链接成为可执行文件hello
6、shell接受用户命令,调用fork函数创建子进程。在子进程中加载execve运行hello
7、在一个时间片中,hello占用了一部分CPU资源
8、在TLB与四级页表支持下的hello的VA到PA的变换实现
9、三级Cache支持下的实现了hello的物理内存访问

至此hello实现了从program到process的转变也就是p2p

10、在hello进程的持续过程中可能出现各种异常和故障
11、最后,hello进程执行完毕之后,shell回收子进程。

最终,hello尘归尘,土归土,从无中来到无中去,实现了020

感悟:看似简单的程序编写包含着十分深刻的道理,计算机系统各个部分是如此的精密而协调,通过一系列操作最终才实现了一个进程的执行。在学习过程中,我感到自己的无知以及计算机系统的浩渺与美丽,想要执行一个进程竟然需要系统如此精妙的配合,这让我对于程序的执行过程有了更加深刻的认识,在优化程序方面也有了更多的想法。

附件
hello.c:hello源文件
hello.i:hello.c预处理后的文本文件
hello.s:hello.i编译后的汇编文件
hello.o:hello.s汇编后的可重定位目标文件
hello:可执行文件

参考文献
[1] cherisegege.什么是重定位?为什么需要重定位?[EB/OL]
https://blog.csdn.net/cherisegege/article/details/80708143
[2]枣面包.Shell——你只需要了解这么多.[EB/OL]
https://blog.csdn.net/weixin_37490221/article/details/80869792?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522159030341019724843312917%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=159030341019724843312917&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v3~pc_rank_v3-2-80869792.first_rank_ecpm_v3_pc_rank_v3&utm_term=shell
[3]Randal E.Bryant.And DavidR.O’Hallaron.Computer Systems:A Programmar’s Perspective.Third Edition.[M]
[4]毛毛雨下A.通俗理解物理地址、逻辑地址、线性地址、虚拟地址、有效地址的区别.[EB/OL].
https://blog.csdn.net/mzjmzjmzjmzj/article/details/84713351?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522159031983019195162509822%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=159031983019195162509822&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allbaidu_landing_v2~default-2-84713351.first_rank_ecpm_v3_pc_rank_v3&utm_term=%E7%BA%BF%E6%80%A7%E5%9C%B0%E5%9D%80
[5]godop.分页存储管理,分段存储管理,段页式存储管理.[EB/OL].
https://blog.csdn.net/godop/article/details/79523457?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522159032372219726869032600%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=159032372219726869032600&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v3~pc_rank_v3-1-79523457.first_rank_ecpm_v3_pc_rank_v3&utm_term=%E9%A1%B5%E5%BC%8F%E5%AD%98%E5%82%A8%E7%AE%A1%E7%90%86

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值