HITICS-2018大作业 hello的一生

第一章 第2节计算机基础知识(软件开发和计算机语言概述) 阅读详情

摘  要
本论文详细介绍了hello程序在linux系统中从生成源代码到成功运行完毕被系统回收的整个过程,按照执行的先后顺序模块化介绍了hello.c在计算机内部是系统具体执行了什么指令、如何执行的、用到了哪些知识等。
本论文参考CSAPP课本的章节内容,以hello.c为示例具体介绍了他的整个生命周期,是课本知识点的浓缩和综合,有助于学生深入浅出地理解这一门课程。
关键词:hello.c,生命周期,CSAPP,P2P,020

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


目  录

第1章 概述    
第2章 预处理    
第3章 编译   
第4章 汇编  
第5章 链接 
第6章 hello进程管理   
第7章 hello的存储管理   
第8章 hello的IO管理   
结论   
附件   
参考文献    


第1章 概述
1.1 Hello简介
P2P是指from program to process。在linux系统中,源文件hello.c经cpp的预处理生成文本文件hello.i,经ccl编译生成汇编文件hello.s,经id链接生成可执行程序hello。在输入命令(./hello)启动该程序后,在shell里OS为其fork,创建子进程,就成为了process。
020是指from zero to zero。hello程序开始运行成为进程后,OS为其execve,映射虚拟内存,调用程序入口时开始载入物理内存,进入main函数执行目标代码,然后分配时间片,执行逻辑控制流,执行正确的IO管理与信号处理来保证程序的正常运行,以及与用户的交互。hello程序运行结束后,父进程回收该子进程,内核删除进程产生的相关数据和分配的结构,恢复程序执行前的状态,实现020。
1.2 环境与工具
硬件:Inter(R)Core(TM)i7-7500U CPU @2.70GHz 2.90GHz
软件:Ubuntu18.04.1 LTS
开发与调试工具:gcc,gdb,HexEdit,readelf等
1.3 中间结果
hello.i 预处理后的文本文件,加载了头文件,进行了宏替换,完成条件编译
hello.s 编译后的汇编文件
hello.o 汇编后的可重定位目标文件,将汇编语言翻译成机器语言指令,并将指令打包成可重定位目标文件。
hello 链接产生的可执行目标文件
hello.elf     hello的ELF格式文件
1.4 本章小结
本章主要介绍了hello文件的P2P和020过程,旨在使人初步了解程序在计算机系统中是如何被执行的,对计算机程序执行的原理及有关文件的作用、来源进行阐述,有利于加深人们对计算机相关知识和相关用语的理解。
(第1章0.5分)
第2章 预处理
2.1 预处理的概念与作用
概念:预处理器cpp根据以字符#开通的命令修改原始.c文件,加载头文件,将引用的所有库展开合并为一个文本文件,进行宏替换,完成条件编译。
作用:(1)展开所有宏定义,处理#define x y格式的语句,用y替代x;
(2)加载头文件,将#include格式的头文件插入到预编译指令的位置;
(3)完成条件编译,处理#if,#ifdef格式的语句;
(4)删除注释;
2.2在Ubuntu下预处理的命令
gcc -E -o hello.i hello.c

可以看到文件夹中生成了hello.i文件

打开hello.i如下图

2.3 Hello的预处理结果解析
hello.c中的代码只有二十多行,而我们打开hello.i可以发现这是一个很大的文件,有三千多行。仔细观察可以发现main函数里的代码没有变化,注释被删除,而头文件部分被三千行的一大坨代码取代,也就是依次展开的头文件的源代码。cpp到默认的环境变量下寻找头文件,如果头文件中仍然存在#define语句等,则cpp继续对此递归展开。这样一来编译器就可以直接将hello.i文件翻译成汇编文件。
2.4 本章小结
本章节简单介绍了c语言文件在编译之前的预处理过程,即.c文件生成.i文本文件的过程,对预处理的含义、具体执行过程和预处理结果进行了解析。

(第2章0.5分)
第3章 编译
3.1 编译的概念与作用
注意:这儿的编译是指从 .i 到 .s 即预处理后的文件到生成汇编语言程序
   概念:编译是指利用编译程序从源语言编写的源程序产生目标程序的过程,这里是将预处理文本文件hello.i翻译成汇编语言程序hello.s的过程。
作用:编译过程是指对预处理生存的.i文件进行一系列词法分析、语法分析、语义分析,最后优化后生成相应的汇编代码文件。具体步骤如下:
(1)词法分析,将字符串转化为内部表示结构;
(2)语法分析,将上一步分析得到的标记流转化生成为一棵语法树;
(3)生成汇编代码,将语法树转化为汇编目标代码。
3.2 在Ubuntu下编译的命令
gcc -S hello.i -o hello.s:

之后就生成了hello.s文件:

打开hello.s如下图:

可以看出已经生成了汇编语言文件hello.s。
3.3 Hello的编译结果解析
3.3.1数据
hello.c中定义的全局变量int sleepsecs,编译器将其编译后变成如下汇编代码:

说明这个变量的大小是4个字节。
3.3.2赋值
(1)赋值语句sleepsecs=2.5,编译器将其编译后变成如下汇编代码:

说明初始化过的全局变量的值被存放在.data节中。
(2)赋值语句i=0,编译器将其编译后变成如下汇编代码:

3.3.3类型转换
变量sleepsecs是int类型的,但是赋值时所赋的值2.5是浮点数,因此这里编译器有一个隐式的数据类型转换,将2.5转换成整数2存入sleepsecs。
3.3.4 算数操作
计数变量i++的语句,编译器将其编译后变成如下汇编代码:

3.3.5 关系操作
判断语句往往编译成cmp系列语句和j系列条件跳转语句的组合,具体参考CSAPP课本中相关部分的介绍。
(1)判断语句argc!=3的,编译器将其编译后变成如下汇编代码:

(2)计数变量i<10的判断语句,编译器将其编译后变成如下汇编代码:

3.3.6 数组/指针/结构操作
取数组的第i位一般是按照取数组头指针加上第i位的偏移量来操作的;指针跟数组类似,如果x表示一个指针,rax表示其存储的寄存器,你要访问*x,那么就是(%rax);结构也是类似的,通过结构在结构体中的偏移量来访问。
printf函数里面的一系列对指针和数组的操作,编译器将其编译后变成如下汇编代码:

3.3.7 控制转移
if,for循环等控制转移语句都是由比较语句和条件跳转来实现的,比较语句被编译器编译成cmp语句,条件跳转则由je、jle等实现。
(1)if (argc!=3) 编译器将其编译后变成如下汇编代码:

(2)for循环语句编译器将其编译后变成如下汇编代码:

3.3.8 函数操作
一个函数的返回值一般存在寄存器eax中,如果要设定返回值的话,那就先将返回值传入eax,然后再用ret语句返回。
(1)输出语句printf("Usage: Hello 1173710111 張淑慧!\n"),首先编译器将输出的字符串进行编译,转换为如下代码:

然后将输出语句编译后变成如下汇编代码:

(2)输出语句printf("Hello %s %s\n",argv[1],argv[2]),首先编译器将输出的字符串进行编译,转换为如下代码:

然后将输出语句编译后变成如下汇编代码:

(3)系统函数sleep(sleepsecs),编译器将其编译后变成如下汇编代码:

3.4 本章小结
本章简单介绍了编译的概念和作用,并以hello.c的编译过程为实例详细剖析了一个c程序是如何被编译器翻译成汇编语言文件hello.s的,并分类展示出不同功能的c语句对应的汇编语句,并简单给出了对应的编译原理。
本章通过实例分析,有助于学生将所学的理论知识与实际样例相结合,更加立体地学习和感受编译原理,有助于加深对计算机执行程序的过程的理解。
(第3章2分)
第4章 汇编
4.1 汇编的概念与作用

概念:汇编是指汇编器(as)将汇编文件hello.s翻译成机器语言指令,并把这些指令打包成一种叫做可重定位目标文件的格式,并将结果保存在目标文件hello.o中。
作用:汇编器是将汇编代码转变成机器可以执行的命令,每一个汇编语句几乎都对应一条机器指令。汇编相对于编译过程比较简单,根据汇编指令和机器指令的对照表一一翻译即可。
4.2 在Ubuntu下汇编的命令
as hello.s -o hello.o

之后就生成了二进制文件hello.o如下:

4.3 可重定位目标elf格式
用readelf打开hello.o文件,命令行为readelf -a hello.o,如下面各图所示。得到的elf格式文件组成如下:(1)ELF头,用于总的描述ELF文件各个信息的段;


(2)节头,描述了.o文件中出现的各个节的类型、位置、所占空间大小等信息;
 
(3)重定位节.rela.text,这个节包含了.text(具体指令)节中需要进行重定位的信息。这些信息描述的位置,在由.o文件生成可执行文件的时候需要被修改(重定位)。在这个hello.o里面需要被重定位的有printf , puts , exit , sleepsecs , getchar , sleep ,rodata里面的两个元素(.L0和.L1字符串)。.rela.eh_frame是eh_frame节的重定位信息。


4.4 Hello.o的结果解析
objdump -d -r hello.o  分析hello.o的反汇编,并请与第3章的 hello.s进行对照分析。
说明机器语言的构成,与汇编语言的映射关系。特别是机器语言中的操作数与汇编语言不一致,特别是分支转移函数调用等。
键入objdump -d -r hello.o命令查看hello.o的反汇编,得到下图:


对比第三章的hello.s(如下图):


可以看出,hello.o的反汇编比hello.s的汇编代码基本相同,只是在一些位置多了些注释,但是每一行汇编代码左侧都多了一行16进制编码:冒号前面的是运行的时候机器指令的位置,后面的是该行汇编代码对应的机器指令。实际上的机器语言是由0和1组成的二进制语句,显示时以16进制形式显示。
另外,汇编器在对hello.s文件进行汇编时,实现了以下操作:
1. 为每条语句加上了具体的地址,全局变量和常量都被安排到了具体的地址里面;
2. 操作数在hello.s里面都是十进制,在到hello.o里面的机器级程序时都是十六进制;
3. 跳转语句jx&jxx原来对应的符号都变成了相对偏移地址;
4. 函数调用时原来的函数名字也被替换成了函数的相对偏移地址。
4.4.1 分支转移
反汇编代码跳转指令的操作数使用的不是段名称如.L3,因为段名称只是在汇编语言中便于编写的助记符,所以在汇编成机器语言之后显然不存在,而是确定的地址。
4.4.2 函数调用
在.s文件中,函数调用之后直接跟着函数名称,而在反汇编程序中,call的目标地址是当前下一条指令。这是因为hello.c中调用的函数都是共享库中的函数,最终需要通过动态链接器才能确定函数的运行时执行地址,在汇编成为机器语言的时候,对于这些不确定地址的函数调用,将其call指令后的相对地址设置为全0(目标地址正是下一条指令),然后在.rela.text节中为其添加重定位条目,等待静态链接的进一步确定。
4.4.3全局变量访问
在.s文件中,访问rodata(printf中的字符串),使用段名+%rip,在反汇编代码中0+%rip,因为rodata中数据地址也是在运行时确定,故访问也需要重定位。所以在汇编成为机器语言时,将操作数设置为全0并添加重定位条目。
4.5 本章小结
本章简单介绍了汇编这一过程,即汇编器(as)将汇编文件hello.s翻译成机器语言指令并存储到hello.o文件中的过程,同样以hello程序为实例,将理论知识与实际操作的过程穿插编排。
本章通过实例分析与理论知识讲解相结合,有助于学生将课本上课学到的知识与实际操作结合,融会贯通,更加深入地学习和感受汇编的过程,有助于加深对汇编语言和汇编过程的理解。
(第4章1分)
第5章 链接
5.1 链接的概念与作用
概念:链接是将各种代码和数据片段收集并组合成一个单一文件的过程,这个文件可被加载到内存并执行。链接可以执行于编译时,也就是在源代码被编译成机器代码时;也可以执行于加载时,也就是在程序被加载器加载到内存并执行时;甚至于运行时,也就是由应用程序来执行。
作用:链接是由叫做链接器的程序执行的。链接器使得分离编译成为可能。链接的存在降低了模块化编程的难度。
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

5.3 可执行目标文件hello的格式
键入readelf -a hello >hello.elf命令生成hello程序的ELF格式文件hello.elf。
打开hello.elf,首先是ELF头部分如下:

节头信息如下:


节头对hello中所有的节信息进行了声明,其中包括大小Size以及在程序中的偏移量Offset,因此根据节头中的信息我们就可以用HexEdit定位各个节所占的区间(起始位置,大小)。其中Address是程序被载入到虚拟地址的起始地址。
5.4 hello的虚拟地址空间
   我们用edb打开hello,可以在Data Dump窗口看见hello加载到虚拟地址中的状况:


可以看出程序是在0x00400000地址开始加载的,结束的地址大约是0x00400fff。
再来分析分析elf里面的Program Headers:

PHDR:程序头表
INTERP:程序执行前需要调用的解释器
LOAD:程序目标代码和常量信息
DYNAMIC:动态链接器所使用的信息
NOTE::辅助信息
GNU_EH_FRAME:保存异常信息
GNU_STACK:使用系统栈所需要的权限信息
GNU_RELRO:保存在重定位之后只读信息的位置
其余的从.dynamic到.strtab节的内容是存放在0x00400fff后面
5.5 链接的重定位过程分析
对比5.3的节头信息和4.3的节头信息,hello相对于hello.o有如下不同:
1. hello.o中的相对偏移地址到了hello中变成了虚拟内存地址
2. hello中相对hello.o增加了许多的外部链接来的函数。
3. hello相对hello.o多了很多的节类似于.init,.plt等
4. hello.o中跳转以及函数调用的地址在hello中都被更换成了虚拟内存地址
分析可得比hello.o多出来如下节表头:
.interp:保存ld.so的路径
.note.ABI-tag
.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.s
我们可以发现,在hello_o.s中调用函数都是使用call+<main+偏移量的做法>,而在hello_.s是直接使用call+<函数名> 的方法来直接调用的。

5.6 hello的执行流程
1. 先是加载程序_init (argc=1, argv=0x7fffffffde38, envp=0x7fffffffde48)
2. 0x00000000004004d0 in _start ()
3. 0x0000000000400480 in __libc_start_main@plt ()
4. 0x0000000000400670 in __libc_csu_init ()
5. 0x0000000000400430 in _init ()
6. 0x00000000004005b0 in frame_dummy ()
7. 0x0000000000400540 in register_tm_clones ()
8. 0x00000000004005f2 in main ()
9. 0x0000000000400460 in puts@plt ()
10. 0x00000000004004a0 in exit@plt ()
11. 0x0000000000400580 in __do_global_dtors_aux ()
12. 0x0000000000400500 in deregister_tm_clones ()
13. 0x00000000004006e4 in _fini ()
注:edb不会用,而且好难用。。。所以以上内容是使用gdb得出
5.7 Hello的动态链接分析
对于动态共享链接库中PIC函数,编译器没有办法预测函数的运行时地址,所以需要添加重定位记录,等待动态链接器处理,为避免运行时修改调用模块的代码段,链接器采用延迟绑定的策略。动态链接器使用过程链接表PLT+全局偏移量表GOT实现函数的动态链接,GOT中存放函数目标地址,PLT使用GOT中地址跳转到目标函数。在dl_init调用之前,对于每一条PIC函数调用,调用的目标地址都实际指向PLT中的代码逻辑,GOT存放的是PLT中函数调用指令的下一条指令地址。
在dl_init调用之后,0x601008和0x601010处的两个8B数据分别发生改变为0x7fd9 d3925170和0x7fd9 d3713680,其中GOT[1]指向重定位表(依次为.plt节需要重定位的函数的运行时地址)用来确定调用的函数地址,GOT[2]指向动态链接器ld-linux.so运行时地址。

在之后的函数调用时,首先跳转到PLT执行.plt中逻辑,第一次访问跳转时GOT地址为下一条指令,将函数序号压栈,然后跳转到PLT[0],在PLT[0]中将重定位表地址压栈,然后访问动态链接器,在动态链接器中使用函数序号和重定位表确定函数运行时地址,重写GOT,再将控制传递给目标函数。之后如果对同样的函数调用,第一次访问跳转直接跳转到目标函数。
因为在PLT中使用的jmp,所以执行完目标函数之后的返回地址为最近call指令下一条指令地址,即在main中的调用完成地址。
5.8 本章小结
本章主要介绍了链接的概念与作用,对hello的ELF格式文件包含的信息进行解析,分析了hello的虚拟地址空间、重定位过程、执行流程、动态链接过程。
本章对链接的步骤和过程进行了详细的分解和解析,这样有利于学生在以后处理相关的问题的时候沉着应对。
(第5章1分)

第6章 hello进程管理
6.1 进程的概念与作用
概念:一个执行中程序的实例。

作用:每次用户通过向shell 输入一个可执行目标文件的名字,运行程序时, shell 就会创建一个新的进程,然后在这个新进程的上下文中运行这个可执行目标文件。应用程序也能够创建新进程,并且在这个新进程的上下文中运行它们自己的代码或其他应用程序。
6.2 简述壳Shell-bash的作用与处理流程
作用::Shell是一个用C语言编写的程序应用程序,他在操作系统中提供了一个用户与系统内核进行交互的界面。
处理流程一般是这样的:
1. 读取用户的输入
2. 分析输入内容,获得输入参数
3. 如果是内核命令则直接执行,否则调用相应的程序执行命令
4. 在程序运行期间,shell需要监视键盘的输入内容,并且做出相应的反应
6.3 Hello的fork进程创建过程
Shell通过调用fork 函数创建一个新的运行的子进程。也就是Hello程序,Hello进程几乎但不完全与Shell相同。Hello进程得到与Shell用户级虚拟地址空间相同的(但是独立的)一份副本,包括代码和数据段、堆、共享库以及用户栈。Hello进程还获得与Shell任何打开文件描述符相同的副本,这就意味着当Shell调用fork 时,Hello可以读写Shell中打开的任何文件。Sehll和Hello进程之间最大的区别在于它们有不同的PID。

6.4 Hello的execve过程
每一个进程都有一段唯一属于自己的内存地址段,在execve运行时,开始先是从0x00400000(对于32位系统来说是0x8048000)开始程序的执行。先是从可执行文件中加载的内容,然后是运行时的堆栈和共享库的存储器映射区域。


当fork之后,子进程调用execve函数(传入命令行参数)在当前进程的上下文中加载并运行一个新程序即hello程序。execve 函数加载并运行可执行目标文件hello, 且带参数列表argv 和环境变量列表envp 。只有当出现错误时,例如找不到hello, execve 才会返回到调用程序。所以,与fork 一次调用返回两次不同, execve 调用一次并从不返回。
6.5 Hello的进程执行
Linux 系统中的每个程序都运行在一个进程上下文中,有自己的虚拟地址空间。当shell 运行一个程序时,父shell 进程生成一个子进程,它是父进程的一个复制。子进程通过execve 系统调用启动加载器。加载器删除子进程现有的虚拟内存段,并创建一组新的代码、数据、堆和栈段。新的栈和堆段被初始化为零。通过将虚拟地址空间中的页映射到可执行文件的页大小的片(chunk), 新的代码和数据段袚初始化为可执行文件的内容。最后,加载器跳转到_start地址,它最终会调用应用程序的main 函数。在内核和前端之前切换的动作被称为上下文切换。
6.6 hello的异常与信号处理
6.6.1 异常种类
hello执行过程中会出现的异常种类有:
(1)中断:SIGSTP:挂起程序
(2)终止:SIGINT:终止程序
6.6.2 各种命令的执行
  1. ctrl-z:这个操作向进程发送了一个sigtstp信号,让进程暂时挂起。
(1)输入ps命令符可以发现hello进程还没有被关闭:

(2)jobs命令可以查看当前的关键命令(ctrl+Z/ctrl+C这类)内容,比如这时候就会返回ctrl+Z表示暂停命令:

(3)pstree是用进程树的方法把各个进程用树状图的方式连接起来:

(4)fg:发送SIGCONT信号继续执行停止的进程:

(5)5.kill -9 pid:发送SIGKILL信号给指定的pid杀死进程:

  2.ctrl-c操作:这个操作向进程发送了一个sigint信号,让进程直接结束,输入ps命令可以发现当前hello进程已经被终止了:

  3.运行过程中脸滚键盘并不影响进程:

6.7本章小结
本章简要阐述了进程的定义和作用,详细介绍了shell的一般处理流程,描述了shell如何在用户和系统内核之间建起一个交互的桥梁,以hello程序为例介绍了shell的基本操作以及各种内核信号和命令,还总结了shell是如何fork新建子进程、execve如何执行进程、hello进程如何在内核和前端中反复跳跃运行的。
(第6章1分)
第7章 hello的存储管理
7.1 hello的存储器地址空间
逻辑地址:又称相对地址,是程序运行由CPU产生的与段相关的偏移地址部分。他是描述一个程序运行段的地址。

物理地址:程序运行时加载到内存地址寄存器中的地址,内存单元的真正地址。他是在前端总线上传输的而且是唯一的。在hello程序中,他就表示了这个程序运行时的一条确切的指令在内存地址上的具体哪一块进行执行。

线性地址:这个和虚拟地址是同一个东西,是经过段机制转化之后用于描述程序分页信息的地址。他是对程序运行区块的一个抽象映射,即一个程序应该在内存的哪些块上运行。
7.2 Intel逻辑地址到线性地址的变换-段式管理
一个逻辑地址由两部份组成,段标识符和段内偏移量。段标识符是由一个16位长的字段组成,称为段选择符。其中前13位是一个索引号。后面3位包含一些硬件细节,如图:

索引号是“段描述符”的索引,很多个段描述符,就组了一个数组,叫“段描述符表”,这样,可以通过段标识符的前13位,直接在段描述符表中找到一个具体的段描述符,这个描述符就描述了一个段,每一个段描述符由8个字节组成,如下图:

 其中Base字段,它描述了一个段的开始位置的线性地址,一些全局的段描述符,就放在“全局段描述符表(GDT)”中,一些局部的,例如每个进程自己的,就放在所谓的“局部段描述符表(LDT)”中,由段选择符中的T1字段表示选择使用哪个,=0,表示用GDT,=1表示用LDT。GDT在内存中的地址和大小存放在CPU的gdtr控制寄存器中,而LDT则在ldtr寄存器中。如下图:

下面是转换的具体步骤:
1. 给定一个完整的逻辑地址[段选择符:段内偏移地址]。
2. 看段选择符的T1=0还是1,知道当前要转换是GDT中的段,还是LDT中的段,再根据相应寄存器,得到其地址和大小。可以得到一个数组。
3. 取出段选择符中前13位,在数组中查找到对应的段描述符,得到Base,也就是基地址。
4. 线性地址 = Base + offset。
7.3 Hello的线性地址到物理地址的变换-页式管理
线性地址(书里的虚拟地址VA)到物理地址(PA)之间的转换通过分页机制完成。而分页机制是对虚拟地址内存空间进行分页。线性地址被分为以固定长度为单位的组,称为页(page)。为了节省空间,引入了一个二级管理模式的机器来组织分页单元。如图:

如图可以看出:
1.分页单元中,页目录是唯一的,它的地址放在CPU的cr3寄存器中,是进行地址转换的开始点;
2.每一个活动的进程,因为都有其独立的对应的虚似内存(页目录也是唯一的),那么它也对应了一个独立的页目录地址。——运行一个进程,需要将它的页目录地址放到cr3寄存器中;
3.每一个32位的线性地址被划分为三部份,面目录索引(10位):页表索引(10位):偏移(12位)。
依据以下步骤进行转换:
1.从cr3中取出进程的页目录地址(操作系统负责在调度进程的时候,把这个地址装入对应寄存器);
2.根据线性地址前十位,在数组中,找到对应的索引项,因为引入了二级管理模式,页目录中的项,不再是页的地址,而是一个页表的地址。(又引入了一个数组),页的地址被放到页表中去了;
3.根据线性地址的中间十位,在页表(也是数组)中找到页的起始地址;
4.将页的起始地址与线性地址中最后12位相加,得到最终我们想要的物理地址。
7.4 TLB与四级页表支持下的VA到PA的变换
下图给出了Core i7 MMU 如何使用四级的页表来将虚拟地址翻译成物理地址。36位VPN 被划分成四个9 位的片,每个片被用作到一个页表的偏移量。CR3 寄存器包含Ll页表的物理地址。VPN 1 提供到一个Ll PET 的偏移量,这个PTE 包含L2 页表的基地址。VPN 2 提供到一个L2 PTE 的偏移量,以此类推。

7.5 三级Cache支持下的物理内存访问
得到物理地址之后,先将物理地址拆分成CT(标记)+CI(索引)+CO(偏移量),然后在一级cache内部找,如果未能寻找到标记位为有效的字节(miss)的话就去二级和三级cache中寻找对应的字节,找到之后返回结果。如下图:

7.6 hello进程fork时的内存映射
mm_struct(内存描述符):描述了一个进程的整个虚拟内存空间
vm_area_struct(区域结构描述符):描述了进程的虚拟内存空间的一个区间

在用fork创建虚拟内存的时候,要经历以下步骤:
1. 创建当前进程的mm_struct,vm_area_struct和页表的原样副本
2. 两个进程的每个页面都标记为只读页面
3. 两个进程的每个vm_area_struct都标记为私有,这样就只能在写入时复制。
7.7 hello进程execve时的内存映射
execve函数调用驻留在内核区域的启动加载器代码,在当前进程中加载并运行包含在可执行目标文件hello中的程序,用hello程序有效地替代了当前程序。加载并运行hello需要以下几个步骤:
1) 删除已存在的用户区域,删除当前进程虚拟地址的用户部分中的已存在的区域结构;
2) 映射私有区域,为新程序的代码、数据、bss和栈区域创建新的区域结构,所有这些新的区域都是私有的、写时复制的。代码和数据区域被映射为hello文件中的.text和.data区,bss区域是请求二进制零的,映射到匿名文件,其大小包含在hello中,栈和堆地址也是请求二进制零的,初始长度为零;
3) 映射共享区域, hello程序与共享对象libc.so链接,libc.so是动态链接到这个程序中的,然后再映射到用户虚拟地址空间中的共享区域内;
4) 设置程序计数器(PC),execve做的最后一件事情就是设置当前进程上下文的程序计数器,使之指向代码区域的入口点。
7.8 缺页故障与缺页中断处理
在虚拟内存的习惯说法中, DRAM 缓存不命中称为缺页(page fault) 
情况1:段错误:首先,先判断这个缺页的虚拟地址是否合法,那么遍历所有的合法区域结构,如果这个虚拟地址对所有的区域结构都无法匹配,那么就返回一个段错误(segment fault)
情况2:非法访问:接着查看这个地址的权限,判断一下进程是否有读写改这个地址的权限。
情况3:如果不是上面两种情况那就是正常缺页,那就选择一个页面牺牲然后换入新的页面并更新到页表。
下图为缺页异常示意图:

7.9动态存储分配管理
printf函数会调用malloc,下面简述动态内存管理的基本方法与策略:
动态内存分配器维护着一个进程的虚拟内存区域,称为堆。分配器将堆视为一组不同大小的块的集合来维护。每个块就是一个连续的虚拟内存片,要么是已分配的,要么是空闲的。已分配的块显式地保留为供应用程序使用。空闲块可用来分配。空闲块保持空闲,直到它显式地被应用所分配。一个已分配的块保持已分配状态,直到它被释放,这种释放要么是应用程序显式执行的,要么是内存分配器自身隐式执行的。分配器分为两种基本风格:显式分配器、隐式分配器。显式分配器:要求应用显式地释放任何已分配的块。隐式分配器:要求分配器检测一个已分配块何时不再使用,那么就释放这个块,自动释放未使用的已经分配的块的过程叫做垃圾收集。
一、 带边界标签的隐式空闲链表
1)堆及堆中内存块的组织结构:

在内存块中增加4B的Header和4B的Footer,其中Header用于寻找下一个blcok,Footer用于寻找上一个block。Footer的设计是专门为了合并空闲块方便的。因为Header和Footer大小已知,所以我们利用Header和Footer中存放的块大小就可以寻找上下block。
2)隐式链表所谓隐式空闲链表,对比于显式空闲链表,代表并不直接对空闲块进行链接,而是将对内存空间中的所有块组织成一个大链表,其中Header和Footer中的block大小间接起到了前驱、后继指针的作用。
3)空闲块合并
因为有了Footer,所以我们可以方便的对前面的空闲块进行合并。合并的情况一共分为四种:前空后不空,前不空后空,前后都空,前后都不空。对于四种情况分别进行空闲块合并,我们只需要通过改变Header和Footer中的值就可以完成这一操作。
二、 显示空间链表基本原理 
将空闲块组织成链表形式的数据结构。堆可以组织成一个双向空闲链表,在每个空闲块中,都包含一个pred(前驱)和succ(后继)指针,如下图: 

使用双向链表而不是隐式空闲链表,使首次适配的分配时间从块总数的线性时间减少到了空闲块数量的线性时间。
维护链表的顺序有:后进先出(LIFO),将新释放的块放置在链表的开始处,使用LIFO的顺序和首次适配的放置策略,分配器会最先检查最近使用过的块,在这种情况下,释放一个块可以在线性的时间内完成,如果使用了边界标记,那么合并也可以在常数时间内完成。按照地址顺序来维护链表,其中链表中的每个块的地址都小于它的后继的地址,在这种情况下,释放一个块需要线性时间的搜索来定位合适的前驱。平衡点在于,按照地址排序首次适配比LIFO排序的首次适配有着更高的内存利用率,接近最佳适配的利用率。
7.10本章小结
本章介绍了储存器的地址空间,讲述了虚拟地址、物理地址、线性地址、逻辑地址的概念,还有进程fork和execve时的内存映射的内容。描述了系统如何应对那些缺页异常,最后描述了malloc的内存分配管理机制。
(第7章 2分)
第8章 hello的IO管理
8.1 Linux的IO设备管理方法
设备的模型化:文件
文件的类型:
1. 普通文件(regular file):包含任意数据的文件。
2. 目录(directory):包含一组链接的文件,每个链接都将一个文件名映射到一个文件(他还有另一个名字叫做“文件夹”)。
3. 套接字(socket):用来与另一个进程进行跨网络通信的文件
4. 命名通道
5. 符号链接
6. 字符和块设备

设备管理:unix io接口
1. 打开和关闭文件
2. 读取和写入文件
3. 改变当前文件的位置
8.2 简述Unix IO接口及其函数
Unix I/O接口:
1.打开文件。一个应用程序通过要求内核打开相应的文件,来宣告它想要访间一个I/O 设备。内核返回一个小的非负整数,叫做描述符,它在后续对此文件的所有操作中标识这个文件。内核记录有关这个打开文件的所有信息。应用程序只需记住这个描述符。
2.Linux shell 创建的每个进程开始时都有三个打开的文件:标准输入(描述符为0) 、标准输出(描述符为1) 和标准错误(描述符为2) 。头文件< unistd.h> 定义了常量STDIN_FILENO 、STOOUT_FILENO 和STDERR_FILENO, 它们可用来代替显式的描述符值。
3.改变当前的文件位置。对于每个打开的文件,内核保持着一个文件位置k, 初始为0。这个文件位置是从文件开头起始的字节偏移量。应用程序能够通过执行seek 操作,显式地设置文件的当前位置为K 。
4.读写文件。一个读操作就是从文件复制n>0 个字节到内存,从当前文件位置k 开始,然后将k增加到k+n 。给定一个大小为m 字节的文件,当k~m 时执行读操作会触发一个称为end-of-file(EOF) 的条件,应用程序能检测到这个条件。在文件结尾处并没有明确的“EOF 符号” 。类似地,写操作就是从内存复制n>0 个字节到一个文件,从当前文件位置k开始,然后更新k 。
5.关闭文件。当应用完成了对文件的访问之后,它就通知内核关闭这个文件。作为响应,内核释放文件打开时创建的数据结构,并将这个描述符恢复到可用的描述符池中。无论一个进程因为何种原因终止时,内核都会关闭所有打开的文件并释放它们的内存资源。

Unix I/O函数:
1.进程是通过调用open 函数来打开一个已存在的文件或者创建一个新文件的:int open(char *filename, int flags, mode_t mode);
open 函数将filename 转换为一个文件描述符,并且返回描述符数字。返回的描述符总是在进程中当前没有打开的最小描述符。flags 参数指明了进程打算如何访问这个文件,mode 参数指定了新文件的访问权限位。
返回:若成功则为新文件描述符,若出错为-1。
2.进程通过调用close 函数关闭一个打开的文件。
int close(int fd);
返回:若成功则为0, 若出错则为-1。
3.应用程序是通过分别调用read 和write 函数来执行输入和输出的。
(1)ssize_t read(int fd, void *buf, size_t n);
read 函数从描述符为fd 的当前文件位置复制最多n 个字节到内存位置buf 。返回值-1表示一个错误,而返回值0 表示EOF。否则,返回值表示的是实际传送的字节数量。
返回:若成功则为读的字节数,若EOF 则为0, 若出错为-1。
(2)ssize_t write(int fd, const void *buf, size_t n);
write 函数从内存位置buf 复制至多n 个字节到描述符fd 的当前文件位置。图10-3 展示了一个程序使用read 和write 调用一次一个字节地从标准输入复制到标准输出。
返回:若成功则为写的字节数,若出错则为-1。
8.3 printf的实现分析
1. 首先查看printf的代码:

printf需要做的事情是:接受一个fmt的格式,然后将匹配到的参数按照fmt格式输出。我们可以发现,首先arg获得第二个不定长参数,即输出的时候格式化串对应的值,其次他调用了两个外部函数,一个是vsprintf,还有一个是write。

2. 查看vsprintf代码:

从上面vsprintf函数可以看出,这个函数的作用是将所有的参数内容格式化之后存入buf,然后返回格式化数组的长度。

3. write函数是将buf中的i个元素写到终端的函数。

综上,printf的输出过程如下:
(1)从vsprintf生成显示信息,显示信息传送到write系统函数;
(2)write函数陷阱-系统调用 int 0x80或syscall.字符显示驱动子程序;
(3)从ASCII到字模库到显示vram(存储每一个点的RGB颜色信息)。
(4)显示芯片按照刷新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点(RGB分量),这样,需要打印的字符串“Hello 1173710111 张淑慧”就显示在了屏幕上。
8.4 getchar的实现分析
(以下格式自行编排,编辑时删除)
异步异常-键盘中断的处理:键盘中断处理子程序。接受按键扫描码转成ascii码,保存到系统的键盘缓冲区。
getchar等调用read系统函数,通过系统调用读取按键ascii码,直到接受到回车键才返回。
1.查看getchar函数:

(1)异步异常-键盘中断的处理:当用户按键时,键盘接口会得到一个代表该按键的键盘扫描码,同时产生一个中断请求,中断请求抢占当前进程运行键盘中断子程序,键盘中断子程序先从键盘接口取得该按键的扫描码,然后将该按键扫描码转换成ASCII码,保存到系统的键盘缓冲区之中。
(2)可以看出,这里面调用了一个read函数,通过系统调用读取按键ascii码,直到接受到回车键才返回。这个read函数是将整个缓冲区都读到了buf里面,返回值是缓冲区的长度。我们可以发现,如果buf长度为0,getchar才会调用read函数,否则是直接将保存的buf中的最前面的元素返回。
8.5本章小结
本章主要介绍了Linux的IO设备管理方法、Unix IO接口及其函数,分析了printf函数和getchar函数。这有助于我们以后在写函数的时候在标准I/O 库没有的情况下编写自己的I/O函数。
(第8章1分)
结论
hello程序的一生:
(1)编写,在键盘鼠标等I/O设备下,hello.c被编写出来并以文件的方式储存在主存里面;
(2)预处理,将hello.c调用的所有外部的库展开合并,预处理成为文本文件hello.i;
(3)编译,将hello.i编译成为汇编文件hello.s;
(4)汇编,将hello.s汇编成为可重定位目标文件hello.o;
(5)链接,链接器将外部文件和hello.o链接在一起成为可执行二进制文件hello;
(6)运行:在shell中输入./hello 1173710111 张淑慧 运行该程序;
(7)创建子进程:shell进程调用fork为其创建子进程,shell调用execve,execve调用启动加载器,加映射虚拟内存,进入程序入口后程序开始载入物理内存,然后进入main函数;
(8)执行指令:CPU为其分配时间片,在一个时间片中,hello享有CPU资源,顺序执行自己的控制逻辑流。hello在执行的过程中可能会遇到异常和信号以及命令,执行异常信号的处理流程;
(9)内存申请和访问:MMU将程序中使用的虚拟内存地址通过页表映射成物理地址,printf会调用malloc向动态内存分配器申请堆中的内存;
(10)结束运行:shell父进程回收子进程,内核删除为这个进程创建的所有数据结构。
(结论0分,缺少 -1分,根据内容酌情加分)
附件
hello.i 预处理后的文本文件,加载了头文件,进行了宏替换,完成条件编译
hello.s 编译后的汇编文件
hello.o 汇编后的可重定位目标文件,将汇编语言翻译成机器语言指令,并将指令打包成可重定位目标文件。
hello 链接产生的可执行目标文件
hello.elf     hello的ELF格式文件
(附件0分,缺失 -1分)
参考文献
[1]  兰德尔 E.布莱恩特. 深入理解计算机系统[第三版]:美国:机械工业出版社,2016.
[2] C语言再学习 -- GCC编译过程https://blog.youkuaiyun.com/qq_29350001/article/details/53339861
[3]  LINUX 逻辑地址、线性地址、物理地址和虚拟地址 https://www.cnblogs.com/zengkefu/p/5452792.html
[4]  Linux内核中的printf实现https://blog.youkuaiyun.com/u012158332/article/details/78675427
[5]  [转]printf 函数实现的深入剖析https://www.cnblogs.com/pianist/p/3315801.html.
[6]  进程的睡眠、挂起和阻塞https://www.zhihu.com/question/42962803
(参考文献0分,确实 -1分)
 

【图像拼接】论文精读:As-Rigid-As-Possible Shape Manipulation(ARAP) 文章目录前言1.摘要2.算法的总体流程总结 前言 图像变形算法 1.摘要 论文提出了一个二维图形互动系统。图形是建立在三角形网格上的,用户只需移动几个网格顶点(限制顶点),系统通过最小化每个三角形的误差计算网格剩余顶点(自由顶点)的位置。 算法分两步: 适当旋转每个三角形。 调整大小。 关键是使用二次度量误差将最小化问题转换成线性方程组,然后再解这个方程组。 刚性形状变形是很难的,论文的研究使其变得简单。 2.算法的总体流程 总的流程分三步: 将图形用三角形网格覆盖 选择三个点(限制顶点) 操纵限 阅读详情

相关推荐

个人信息保护合规审计人员(中级)能力测试试卷

本文是关于个人信息保护合规考试的试题解析,内容涵盖《个人信息保护法》相关规定。试卷包含单选题、多选题、判断题、简答题和案例分析题五种题型,总分100分,考试时间120分钟。试题重点考察个人信息处理的基本原则、敏感个人信息处理要求、合规审计流程、个人信息保护影响评估等内容。通过案例分析题详细解析了人脸识别登录、数据共享、跨境传输等场景下的合规要求。参考答案均严格依据《个人信息保护法》等法律法规,为个人信息处理活动提供了明确的合规指引。

qq_41525079的博客 848

程序人生-Hello’s P2P

程序人生-Hello’s P2P 第1章 概述 1.1 Hello简介 我是Hello,我是每一个程序猿的初恋(羞 羞……),我是第一个第一个玩 P2P和020的 From Program to Process: 当hello一行一行的键入.c文件,它的一生就此开始,经过编译预处理器(cpp)的编译预处理变成.i文件,经过ccl的编译变成.s文件,as的汇编变成可重定位目标文件.o,链接器(ld)...

qq_43614606的博客 544

告别拼音!用VSCode+Dosbox-X搞定汇编语言课程设计里的中文姓名显示

本文详细介绍了如何利用VSCode和Dosbox-X解决汇编语言课程设计中中文姓名显示的问题。通过配置开发环境、理解GB2312编码及正确使用汇编指令,学生可以告别拼音显示,实现中文字符的正确输出。文章还提供了完整的代码示例和常见问题排查方法,帮助读者快速掌握这一实用技能。

weixin_30872337的博客 424

哈工大csapp 大作业 hello的一生

Hello的一生第一章 概述1.1 Hello简介1) From Program to Process2) FROM ZERO

weixin_51741633的博客 513

Android双目摄像头(RGB+IR)实时预览与人脸活体检测实战指南

本文详细介绍了Android双目摄像头(RGB+IR)实时预览与人脸活体检测的实战指南。通过双摄同步预览、人脸检测与活体判断等技术实现,提升安全认证的准确性和鲁棒性。文章还提供了开发环境搭建、常见问题解决方案及性能优化建议,帮助开发者快速掌握双目摄像头在Android平台的应用。

vulkan6gpu的博客 685

VMware Workstation Pro 16 安装 Ubuntu 20.04

VMware Workstation Pro 16 安装 ubuntu 20.04目录环境VMware Workstation下载Ubuntu 20.04下载安装过程 目录 环境 Windows 10 Workstation 16 Pro for Windows Ubuntu 20.04 LTS 64位 desktop版本 VMware Workstation下载 链接: https://www.vmware.com/products/workstation-pro/workstation-pro-eval

qq_45642410的博客 1万+

2022 HIT-ICS大作业

计算机系统 大作业 题 目 程序人生-Hello’s P2P 专 业 计算学部 指 导 教 师 史先俊    计算机科学与技术学院 2022年5月 摘 要 本文通过一个简单的hello.c 的程序来分析一个计算机对一段代码的详细处理过程,包括预处理、编译、汇编、链接阶段,进入到内存,各级cache,最后在I/O中输出,最后被回收...

qq_63312644的博客 1419

从GitHub到海浪模拟:手把手教你配置WAVEWATCHⅢ 6.07.0的完整开发与测试环境

本文详细指导如何在Ubuntu系统中配置WAVEWATCHⅢ 6.07.0的开发与测试环境,涵盖虚拟机设置、依赖安装、源码编译及案例验证的全流程。通过步骤化教程,帮助科研人员快速搭建高效的海浪模拟平台,提升海洋数值模拟的研究效率。

weixin_42568801的博客 322

HIT2023CSAPP大作业-程序人生Hello’sP2P

Hello的P2P是指hello.c文件从可执行程序(Program)变为运行时进程(Process)的过程。在Linux系统下,hello.c 文件依次经过cpp预处理、ccl编译、as 汇编、ld 链接最终成为可执行目标程序hello。打开shell,输入命令./hello后,shell 通过fork产生子进程,hello 便从可执行程序(Program)变成为进程(Process)。图 1 生成可执行文件的过程。

qq_62651433的博客 594

ais信号接收设备_国内首款基于软件无线电技术的AIS基站投入测试使用

星网宇达子公司北京凯盾环宇科技有限公司经过多年的潜心研发,成功研制出国内首台基于软件无线电(SDR)的CATON 9011 AIS基站。该基站采用软件无线电技术,利用软件数字技术代替传统的模拟电路,大大的降低了模拟器件的使用率,提高了基站的可靠性和使用年限。CATON 9011 AIS基站研制依据ITU-R M.1371-5、IEC 62320-1、IEC 61162-1等国际标准,兼容...

weixin_29057163的博客 2333

SAP ERPsim生产拓展实验报告

ERP课的实验和实践,也是SAP竞赛玩的东西,除了界面不华丽外很像游戏而且是团队型的pvp大乱斗

m0_67262022的博客 2020

哈工大2022秋计算机系统大作业——程序人生

哈工大2022秋计算机系统大作业——漫游hello程序的一生,就是对计算机系统的一次漫游

qq_62225979的博客 2172

银河麒麟桌面系统 必会操作 | 加装双系统(麒麟桌面系统+Windows系统)的详细方法(含常见故障和解决方法)

装好麒麟桌面操作系统的电脑上、再加装Windows 操作系统的详细方法;和在已经装好Windows系统的电脑上、再加装麒麟桌面操作系统的详细方法;含加装双系统过程中常见问题的解决方法。

qq_33216613的博客 2397

HITICS-2018大作业报告

计算机系统 大作业 题 目 程序人生-Hello’s P2P 计算机科学与技术学院 2018年12月 摘 要 摘要是论文内容的高度概括,应具有独立性和自含性,即不阅读论文的全文,就能获得必要的信息。摘要应包括本论文的目的、主要内容、方法、成果及其理论与实际意义。摘要中不宜使用公式、结构式、图表和非公知公用的符号与术语,不标注引用文献编号,同时避免将摘要写成目录式的内容介绍。 关键词:comput...

cobracanary的博客 1106

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

HIT CS:APP 计算机系统大作业 《程序人生-Hello’s P2P》

HIT CS:APP 计算机系统大作业 程序人生-Hello’s P2P Hello的自白 我是Hello,我是每一个程序猿¤的初恋(羞羞……) l却在短短几分钟后惨遭每个菜鸟的无情抛弃(呜呜……),他们很快喜欢上sum、sort、matrix、PR、AI、IOT、BD、MIS……,从不回头。 l只有我自己知道,我的出身有多么高贵,我的一生多么坎坷! l多年后,那些真懂我的大佬(也是曾经的菜鸟一...

TWW 2332

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

HITICS || 2018大作业 程序人生 Hello's P2P

摘 要   本文通过分析一个hello.c的完整的生命周期,从它开始被编译,到被汇编、链接、在进程中运行,讲解了Linux计算机系统执行一个程序的完整过程。   关键词:操作系统,进程,程序的生命周期 目 录 第1章 概述- 4 - 1.1 Hello简介 - 4 - 1.2 环境与工具 - 4 - 1.3 中间结果 - 4 - 1.4 本章小结 - 4 - 第2章 预...

weixin_30621919的博客 149

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

【ICS】HIT 2018 计算机系统 大作业 《程序人生-Hello’s P2P》

计算机系统大作业:程序人生-Hello’s P2P 摘 要 为对计算机系统有更好的理解和认识,本文对简单的hello程序从代码到运行再到最后终止过程的底层实现进行了分析,描述了与之相关的计算机组成与操作系统的相关内容。基于Linux平台,通过gcc、objdump、gdb、edb等工具对一段程序代码预处理、编译、汇编、链接与反汇编的过程进行分析与比较,并且通过shell及其他Linux内置程序对进...

无极阁 3120

《R语言机器学习:实用案例分析》——2.2节机器学习算法

本节书摘来自华章社区《R语言机器学习:实用案例分析》一书中的第2章,第2.2节机器学习算法,作者[印度] 拉格哈夫·巴利(Raghav Bali)迪潘简·撒卡尔(Dipanjan Sarkar),更多章节内容可以访问云栖社区“华章社区”公众号查看 2.2 机器学习算法目前为止,我们已经大致了解了机器学习。我们理解了机器学习的定义是指,计算机程序在经验E形...

weixin_33704591的博客 359

哈工大计算机系统大作业2022

计算机系统 大作业 题 目程序人生-Hello’s P2P 专 业 计算学部 学   号 120L020401 班 级2003011 学 生 王翔宇 指 导 教 师郑贵滨 计算机科学与技术学院 2021年5月 ...

Wxy_ppChina的博客 1215

HIT-ICS大作业-程序人生

1.1Hello程序最初以hello.c的文件存放在磁盘中,之后通过我们编译器驱动器(gcc)的编译下,首先进行预处理,生成hello.i文件,主要是展开头文件并将定义的宏赋值。然后经过编译步骤,生成汇编代码,也就是hello.s文件。之后通过汇编器(AS)对文件进行进一步转化,生成hello.o文件(可重定位目标文件)之后再通过链接器(LD)链接,生成可执行文件。

iburny的博客 588

计算机系统大作业-程序人生

摘 要 关键词:计算机系统;From Program to Process;From Zero-0 to Zero-0; 本文作者是一名本科学生,在32学时的计算机系统课程学习后,对本课程所学进行的回顾与整理。文章围绕计算机学习之初的hello程序展开,共分为三个部分: 第一部分(章节1)对hello进行简单介绍。 第二部分(章节2、3、4、5)对hello进行了预处理、编译、汇编、链接,将其从c文件转变为可执行文件。 第三部分(章节6、7)展示了he...

m0_52993802的博客 822

HIT-ICS大作业

"Hello" 程序的自白通过拟人化的描述,讲述了一个简单的 hello.c 程序从编写到执行整个过程,以及计算机各个部分在其中所扮演的角色。在书上Hello的成长可以简单表示为下图图1.1P2P,From Program to Process,从程序到进程,编写 hello.c 程序并保存后,经过预处理器处理指令生成预处理后的代码,编译器将其翻译成汇编代码,汇编器再转换为机器代码生成目标文件,链接器将目标文件与库链接成可执行文件。

f157516的博客 883

哈工大计算机系统大作业 程序人生-Hello’s P2P From Program to Process

2022 HIT CSAPP大作业

Stella030的博客 1341

哈工大--计算机系统大作业--程序人生

从程序到进程。Hello的一生和其他所以计算机程序一样,首先需要被程序猿用C,JAVAPython等高级程序语言编写成程序,然后在计算机系统中需要经过预处理、编译、汇编、链接等一系列的复杂动作才可以生成一个可执行目标文件。在shell中启动,调用fork函数创建进程,调用execve函数加载并运行Hello,通过内存映射,分配空间等让Hello与其他进程并发进行,到这里Hello就顺利变成了进程。从0到0Hello没有被运行的时候,不占用任何内存。我们打开。

m0_61925618的博客 854

哈工大计算机系统大作业 程序人生

Linux中使用如下指令进行编译1.开始:_start、_libc_start_main2.执行:_main、_printf、_exit、_sleep、_getchar3.退出:exit程序名称地址_start0x4010f00x2f12271dmain0x401125_printf0x401040_exit0x401070_sleep0x401080_getchar0x401050。

essds的博客 592

计算机系统郑贵滨,哈尔滨工业大学计算机科学与技术学院/国家示范性软件学院研究生考研导师简介-郑贵滨...

哈尔滨工业大学计算机科学与技术学院/国家示范性软件学院研究生考研导师简介-郑贵滨本站小编 Free考研网/2019-05-25基本信息科学研究教育教学论文专著基本信息/Basic Information郑贵滨,男,汉族,1973年生。博士,副教授;哈尔滨工业大学计算机学院 语音处理实验室教师。 承担并完成了多项部级和地方的科研项目,在国内外期刊、国际会议发表文章20余篇,其中EI和ISTP收录...

weixin_31943957的博客 593
上一篇: codevs1213 解的个数-----------数论/扩展欧几里得
下一篇: 软件构造Lab1——实验报告
zero_from
博客等级 码龄10年 11粉丝 61原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值