计算机系统
大作业
题 目 程序人生-Hello’s P2P
专 业 计算机科学与技术
学 号 2022111101
班 级 2203101
学 生 郝永克
指 导 教 师 史先俊
计算机科学与技术学院
2023年4月
本论文以简单的hello程序贯穿全文,详细论述程序从program到process最后被回收的过程,包括预处理,编译,汇编,链接等过程,从而展示程序的完整周期。并且展示进程等计算机重要概念,深入理解计算机运行程序时对异常的处理,提高对计算机底层思路的理解水平
关键词:hello;预处理;汇编;编译;链接;运行
目 录
第1章 概述
1.1 Hello简介
Hello程序是简单的输出学号等信息的program,从程序到运行进过几个过程,首先是预处理器对hello.c进行预处理,然后经过编译器编译以及汇编过程后,再由链接器进行链接操作生成可执行文件hello,存放在磁盘中。当运行时,可执行文件从磁盘读取到内存中,shell为hello创建进程并调用加载器加载hello的可执行文件,为其提供虚拟地址空间等,然后在CPU等硬件设备处理指令以及数据的操作下,hello程序开始运行,运行时会出现许多异常,这些会通过异常处理机制逐一处理,最后到运行结束,操作系统结束hello进程,释放其占用的一切志愿,返回shell,整个hello生命周期结束。
1.2 环境与工具
硬件环境: CPU:AMD Ryzen7 5800H,16GB内存。
系统环境: 虚拟机:Ubuntu 20.04.4 LTS,VMware Workstation 16
工具: 文本编辑器gedit,反汇编工具objdump,编译环境gcc等。
1.3 中间结果
列出你为编写本论文,生成的中间结果文件的名字,文件的作用等。
- hello.i 预处理生成的文件
- hello.s 编译后生成的文件
- hello.o 汇编之后生成的可重定位目标文件
- hello 链接后生成的可执行目标文件
- hello_o_disassembler.txt hello.o的反汇编代码
- hello_disassembler.txt hello.o的反汇编代码
- hello_o_elf.txt hello.o的ELF文件
1.4 本章小结
本章介绍了hello程序的运行周期,列举出实验的环境以及工具,并且展示出本次实验所产生的中间文件及其作用
第2章 预处理
2.1 预处理的概念与作用
概念:预处理指的是程序在编译之前进行的处理,是计算机在处理一个程序时所进行的第一步处理,可以进行代码文本的替换工作,但是不做语法检查。
作用:预处理是为编译做的准备工作,能够对源程序. c文件中出现的以字符“#”开头的命令进行处理,包括宏定义、文件包含、条件编译等,最后将修改之后的文本进行保存,生成. i文件
2.2在Ubuntu下预处理的命令
预处理命令:gcc hello.c -E -o hello.i(将预处理得到结果放入hello.i中)
2.3 Hello的预处理结果解析
首先是hello.c文件的一些基本信息如图:
然后是hello.c涉及到的所有头文件的信息如图:
其次是头文件中所定义的数据类型如图:
然后是头文件中的函数声明部分以及struct结构声明部分如图:
最后是我们的hello.c程序部分:
2.4 本章小结
本章对预处理过程进行展示,包括预处理的命令行指令,以及预处理后产生的hello.i文件解析,我们能发现预处理扩展了很多头文件内容,但hello程序仅仅使用了其中一小部分。
第3章 编译
3.1 编译的概念与作用
编译概念:编译是指将一种高级语言代码(如Java、C++等)翻译成另一种形式(如机器语言)的过程。
编译作用:将高级语言代码转化为计算机可以理解的机器语言代码,便于计算机执行
3.2 在Ubuntu下编译的命令
编译命令行:gcc -S hello.i -o hello.s如图:
3.3 Hello的编译结果解析
3.3.1常量
常数用立即数表示,例如原程序中的argc与4比较,其汇编代码如图,$4表示立即数4
3.3.2局部变量
局部变量存放在寄存器或栈中,例如程序中的局部变量i,其存放在%rbp-4的位置
3.3.3赋值
赋值语句用mov操作表示,例如源代码中i=0,汇编代码如图
3.3.4算术操作
算数操作用add,sub等操作表示,例如源代码中的i++语句,其汇编代码如图:
3.3.5关系操作
关系操作例如==,!=等判断语句,在cmp操作实现,并产生条件码,之后jmp根据条件码进行跳转,例如源代码中判断argc!=4语句,其汇编代码如图:
3.3.6控制转移
控制转移包括if,while等使用jmp操作符实现,例如源代码中if(argc!=4){
printf("用法: Hello 学号 姓名 秒数!\n");
exit(1);
}语句,其汇编代码如图:
其中cmpl判断argc与常数4的大小,并产生条件码,je跳转指令根据条件码执行跳转操作
例如源代码中for(i=0;i<8;i++),其汇编代码如图:
原理同上
3.3.7函数操作
利用call指令来调用函数,将函数需要的参数存放在寄存器中或栈中来进行参数传递,函数调用结束之后,返回值保存在寄存器%rax中。例如源代码中的main函数
main函数的参数存放在寄存器中
对printf和atio函数的调用使用call指令完成。其汇编代码如图:
函数返回值存放在寄存器%rax之中,如图
3.4 本章小结
本章介绍了编译的概念以及过程,以及编译的命令行输入。此外,通过hello函数分析了c语言如何转换成为汇编代码,介绍了汇编代码如何实现变量、常量、传递参数以及分支和循环,以及函数调用各部分
第4章 汇编
4.1 汇编的概念与作用
汇编概念:汇编器将.s 文件翻译成机器语言指令,把这些指令打包成一种叫可重定位目标程序的格式,并将结果保存在目标文件(后缀为.o)中。
汇编作用:将汇编代码转换成真正机器可以读懂的二进制代码。
4.2 在Ubuntu下汇编的命令
汇编命令行:as hello.s -o hello.o
4.3 可重定位目标elf格式
ELF头文件:
包含了系统信息,编码方式,ELF头大小,节的大小和数量等等一系列信息
节头目表:描述各个节的大小,类型,位置等信息
重定位节
各个段引用的外部符号等在链接时需要通过重定位对这些位置的地址进行修改。链接器会通过重定位节的重定位条目计算出正确的地址,hello.o需重定位:.rodata中的模式串,puts,exit,printf,slepsecs,sleep,getchar等符号
符号表:符号表中存放程序中定义的全局变量以及函数的信息
4.4 Hello.o的结果解析
对hello.o进行反汇编,并展示反汇编代码
对比分析:
在数的表示上,hello.s中的操作数表现为十进制,而hello.o反汇编代码中的操作数为十六进制。
在控制转移上,hello.s使用.L2和.LC1等段名称进行跳转,而反汇编代码使用目标代码的虚拟地址跳转。不过目前留下了重定位条目,跳转地址为零。它们将在链接之后被填写正确的位置。
在函数调用上,hello.s直接call函数名称,而反汇编代码中call的是目标的虚拟地址。但和上一条的情况类似,只有在链接之后才能确定运行执行的地址,目前目的地址是全0,并留下了重定位条目。
4.5 本章小结
本章主要介绍了汇编的概念及其作用,并介绍了可重定位目标文件ELF格式构成,以及对hello.o的解析结果进行了分析,感受了从汇编语言到机器语言的过程
第5章 链接
5.1 链接的概念与作用
链接概念:链接是将各种不同文件(主要是可重定位目标文件)的代码和数据综合在一起,通过符号解析和重定位等过程,最终组合成一个可以在程序中加载和运行的单一的可执行目标文件的过程。
链接作用:链接令分离编译成为可能,方便了程序的修改和编译:无需重新编译整个工程,而是仅编译修改的文件。
链接还有利于构建共享库。源程序节省空间而未编入的常用函数文件(如printf.o)进行合并,生成可以正常工作的可执行文件。
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列举出ELF各部分
ELF文件头:
节头:描述了各个节的大小、偏移量和其他属性。链接器链接时,会将各个文件的相同段合并成一个大段,并且根据这个大段的大小以及偏移量重新设置各个符号的地址,各节的信息在节头表中展示出来
程序头:
段节:
重定位节和符号表:
版本信息:
5.4 hello的虚拟地址空间
使用edb加载hello如图:
可以根据节头表查看各段的起始位置,在edb中转到相应地址,可以看到虚拟地址空间中的内容。
5.5 链接的重定位过程分析
对hello反汇编如图
查看反汇编文件:
与hello.o的反汇编文件对比可以发现
(1)Hello的反汇编相较于hello.o的反汇编,每行指令都有唯一的虚拟地址,这是因为hello经过链接,已经完成重定位,每条指令的地址关系已经确定。
(2)扩充了很多函数代码,增加了.init段和.plt段,包括程序加载后执行main前的一些准备工作,以及hello需要用到的一些库函数的定义,这是因为动态链接器将共享库中hello.c用到的函数加入可执行文件中。
- 原本在hello.o中等待重定位而暂时置0的地址操作数,成功进行了重定位,并计算了偏移量,被设置为了虚拟地址空间中的地址。
链接过程描述:链接器在重定位步骤中,合并输入模块并将运行时地址赋给输入模块定义的每个节、符号。当这一步完成时,程序中的每条指令和全局变量才拥有唯一的运行时内存地址。
5.6 hello的执行流程
使用edb执行hello其调用与跳转的各个子程序名或程序地址:
5.7 Hello的动态链接分析
在elf文件中可以找到:
进入edb查看:
利用代码段和数据段的相对位置不变的原则计算变量的正确地址。而对于库函数,需要plt、got的协作。plt初始存的是一批代码,它们跳转到got所指示的位置,然后调用链接器。初始时got里面存的都是plt的第二条指令,随后链接器修改got,下一次再调用plt时,指向的就是正确的内存地址。plt就能跳转到正确的区域。
5.8 本章小结
本章介绍了链接的定义及过程,展示其反汇编与hello.o反汇编的差别,理解链接的结果:将各种不同文件(主要是可重定位目标文件)的代码和数据综合在一起,并且介绍了hello的执行过程中的过程调用情况,以及hello的动态链接分析。
第6章 hello进程管理
6.1 进程的概念与作用
进程概念:正在运行的程序的一个实例
作用:进程是对正在运行的程序过程的抽象;实现角度上,进程是一种数据结构,目的在于清晰地刻画动态系统的内在规律,有效管理和调度进入计算机系统主存储器运行的程序。
6.2 简述壳Shell-bash的作用与处理流程
作用:Shell 应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。
处理流程:
(1)从终端读入输入的命令;
(2)将输入字符串切分获得所有的参数;
(3)如果是内置命令则立即执行;
(4)否则调用相应的程序执行;
(5)shell 应该接受键盘输入信号,并对这些信号进行相应处理。
6.3 Hello的fork进程创建过程
当Hello父进程调用fork 时,操作系统会复制当前进程的副本,包括代码、数据和堆栈等,从而生成一个新的子进程。这两个进程几乎是相同的,但它们有着不同的PID。父子进程之间的执行是并发的,它们在fork调用之后分别继续执行。fork的返回值在父进程中是子进程的PID,而在子进程中是0,这样可以通过返回值的不同来区分执行流。因为进程的地址空间是独立的,之后父子进程可以独立地执行各自的任务,互不干扰。
6.4 Hello的execve过程
execve 是一个在 Unix 系统中的系统调用,用于在当前进程中加载并执行一个新调用execve时,操作系统会用指定的可执行文件替换当前进程的地址空间,包括代码、数据和堆栈等。新程序的执行从其main函数开始,完全取代了原始进程的执行。这个过程包括(1)打开指定的可执行文件;(2)加载其代码和数据到内存;(3)设置新程序的堆栈和参数;(4)最终将控制权转交给新程序。
6.5 Hello的进程执行
6.5.1 上下文:
上下文就是内核重新启动一个被抢占的进程所需要恢复的原来的状态,由寄存器、程序计数器、用户栈、内核栈和内核数据结构等对象的值构成。
6.5.2 进程时间片:
进程的运行本质上是CPU不断从程序计数器 PC 指示的地址处取出指令并执行,值的序列叫做逻辑控制流。操作系统会对进程的运行进行调度,执行进程A->上下文切换->执行进程B->上下文切换->执行进程A->… 如此循环往复。 在进程执行的某些时刻,内核可以决定抢占当前进程,并重新开始一个先前被抢占了的进程,这种决策就叫做调度,是由内核中称为调度器的代码处理的。当内核选择一个新的进程运行,我们说内核调度了这个进程。在内核调度了一个新的进程运行了之后,它就抢占了当前进程,并使用上下文切换机制来将控制转移到新的进程。在一个程序被调运行开始到被另一个进程打断,中间的时间就是运行的时间片。
6.5.3 调度的过程:
在对进程进行调度的过程,操作系统主要做了两件事:加载保存的寄存器,切换虚拟地址空间。
6.5.4 用户态与核心态转换:
为了能让处理器安全运行,需要限制应用程序可执行指令所能访问的地址范围。因此划分了用户态与核心态。
核心态可以说是拥有最高的访问权限,处理器以一个寄存器当做模式位来描述当前进程的特权。进程只有故障、中断或陷入系统调用时才会得到内核访问权限,其他情况下始终处于用户权限之中,保证了系统的安全性。
6.6 hello的异常与信号处理
hello可能出现的异常及处理方式:
- 中断:来自处理器外部的I/O设备信号的结果,由中断处理程序处理,处理后总是返回到下一条指令
- 陷阱:有意的异常,利用syscall指令请求系统服务,异常处理程序处理,这个处理程序解析参数,并调用适当的内核程序,最后总是返回到下一条指令
- 故障:潜在可恢复的错误,可能被故障处理程序修正,可能返回到当前指令
- 终止:不可恢复的错误,不会返回.
产生信号种类:
处理方式:接收信号后,进程可以忽略这个信号,终止或者通过一个称为信号处理程序的用户层函数捕获这个信号
以下为例子:
1.正常运行:
2.按回车:不影响程序正
常运行
- 按ctrl+z:发送SIGTSTP信号,进程暂停被挂起
- 按ctrl+c:发送SIGINT信号,进程终止
Ctrl+z后运行命令
5.1.ps命令:
5.2.jobs命令:
5.3pstree命令:
5.4.fg命令:
5.5.kill命令:
6.7本章小结
本章主要介绍了进程及进程的创建,进程的运行,以及执行过程,此外介绍了运行过程中可能出现的异常以及信号及其对应的处理方式。
第7章 hello的存储管理
7.1 hello的存储器地址空间
1.逻辑地址(Logical Address)是指由程序产生的与段相关的偏移地址部分。在这里指的是hello.o中的内容。
2.线性地址(Linear Address)是逻辑地址到物理地址变换之间的中间层。程序hello的代码会产生段中的偏移地址,加上相应段的基地址就生成了一个线性地址。
3.虚拟地址:CPU启动保护模式后,程序hello运行在虚拟地址空间中。注意,并不是所有的“程序”都是运行在虚拟地址中。CPU在启动的时候是运行在实模式的,Bootloader以及内核在初始化页表之前并不使用虚拟地址,而是直接使用物理地址的。
4.物理地址:放在寻址总线上的地址。放在寻址总线上,如果是读,电路根据这个地址每位的值就将相应地址的物理内存中的数据放到数据总线中传输。如果是写,电路根据这个地址每位的值就在相应地址的物理内存中放入数据总线上的内容。物理内存是以字节(8位)为单位编址的。
7.2 Intel逻辑地址到线性地址的变换-段式管理
逻辑内存地址由两个部分组成:段选择符和偏移量。逻辑地址通过这两个部分经过一系列的变换得到线性地址如图所示。以段选择符为索引,在GDT或LDT中找到对应的段描述符。将段描述符中的基地址与偏移量相加,得到线性地址
7.3 Hello的线性地址到物理地址的变换-页式管理
页式管理是一种内存空间存储管理的技术,页式管理分为静态页式管理和动态页式管理。将各进程的虚拟空间划分成若干个长度相等的页(page),页式管理把内存空间按页的大小划分成片或者页面(page frame),然后把页式虚拟地址与内存地址建立一一对应页表,并用相应的硬件地址变换机构,来解决离散地址变换问题。页式管理采用请求调页或预调页技术实现了内外存存储器的统一管理。
7.4 TLB与四级页表支持下的VA到PA的变换
如图所示,CPU产生虚拟地址VA,并将其传送至MMU,MMU使用前36位VPN作为TLBT(前32位)+TLBI(后4位)在TLB中进行匹配,若命中,则得到PPN(40位)与VPO(12位)组合成物理地址PA(52位)。若TLB没有命中,则MMU向页表中查询,由CR3确定第一级页表的起始地址,VPN1(9位)确定在第一级页表中的偏移量,查询出PTE,如果在物理内存中且权限符合,则执行下一步确定第二级页表的起始地址,以此类推,最终在第四级页表中查询到PPN,与VPO组合成PA,并向TLB中添加条目。
7.5 三级Cache支持下的物理内存访问
CPU将一条虚拟地址VA传送到MMU按照7.4所述的操作获得了物理地址PA。如上图71右半部分所示,根据cache大小组数的要求,将PA分为CT(标记位)、CI(组索引)、CO(块偏移)。根据CI寻找到正确的组,依次与每一行的数据比较,有效位有效且标记位一致则命中。如果命中,直接返回想要的数据。如果不命中,就依次去L2、L3、主存判断是否命中,命中时将数据传给CPU同时更新各级cache的储存。
7.6 hello进程fork时的内存映射
当fork函数被当前进程调用时,内核为新进程创建各种数据结构,并分配给它一个唯一的PID。为了给这个新进程创建虚拟内存,它创建了当前进程的mm_struct、区域结构和页表的原样副本。当fork在新进程中返回时,新进程现在的虚拟内存刚好和调用fork时存在的虚拟内存相同。当这两个进程中的任何一个后来进行写操作时,写时复制机制就会创建新页面,因此,也就为每个进程保持了私有地址空间的抽象概念。
7.7 hello进程execve时的内存映射
1)在bash中的进程中执行了如下的execve调用:execve("hello",NULL,NULL);
2)execve函数在当前进程中加载并运行包含在可执行文件hello中的程序,用hello替代了当前bash中的程序。
3)删除已存在的用户区域。
4)映射私有区域:代码和数据区域被映射为.text区和.data区,bss区域是请求二进制零的,映射到匿名文件,栈和堆区域也是请求二进制零的,初始长度为零。
5)映射共享区域
6)设置程序计数器(PC):设置当前进程的上下文中的程序计数器到代码区域的入口点。
7.8 缺页故障与缺页中断处理
缺页异常的处理:
(1)缺页异常的产生:当程序尝试访问一个虚拟地址,而对应的页面不在物理内存中时,就会发生缺页故障。地址翻译硬件从内存中读取CPU引用信息对应的PTE,从有效位推断出对应的页未被缓存,触发缺页异常。 在进入异常处理程序之前,硬件会自动保存一些寄存器的值,以便在中断处理结束后能够正确地恢复执行。
(2)缺页异常处理程序:缺页异常调用缺页异常处理程序,该程序会选择一个牺牲页,若此页已被修改,内核会将其复制会磁盘。无论哪种情况,内核都会修改相应页表条目,反映牺牲页不再缓存在主存中。异常处理程序将缺页对应的页面从磁盘加载到主存中,更新页表,随后返回。
(3)正常继续运行:恢复之前保存的寄存器值,以便继续执行用户程序。此时,用户程序能够重新访问之前导致缺页故障的虚拟地址。由于页面已经加载到物理内存,重新执行引起缺页故障的指令。这次访问将成功完成。
7.9动态存储分配管理
动态储存分配管理使用动态内存分配器(如malloc)来进行。动态内存分配器维护着一个进程的虚拟内存区域,称为堆。分配器将堆视为一组不同大小的块的集合。每个块就是一个连续的虚拟内存页,要么是已分配的,要么是空闲的。已分配的块显式地保留为供应用程序使用。空闲块保持空闲,直到它显式地被应用所分配。一个已分配的块保持已分配的状态,直到它被释放,这种释放要么是应用程序显式执行的,要么是内存分配器自身隐式执行的。动态内存分配主要有两种基本方法与策略:
7.9.1 带边界标签的隐式空闲链表分配器管理
带边界标记的隐式空闲链表的每个块是由一个字的头部、有效载荷、(可能的)额外填充以及一个字的尾部组成。
隐式空闲链表:空闲块通过头部的大小字段隐含地连接着。分配器遍历堆中所有的块,间接地遍历整个空闲块的集合。
当一个应用请求一个k字节的块时,分配器搜索空闲链表,查找一个足够大的可以放置所请求块的空闲块。分配器有三种放置策略:首次适配、下一次适配和最佳适配。分配器在面对释放一个已分配块时,可以合并相邻的空闲块,其中一种简单的方式,是利用隐式空闲链表的边界标记来进行合并。
7.9.2 显式空间链表管理
显式空闲链表是将堆的空闲块组织成一个双向链表,在每个空闲块中,都包含一个前驱与一个后继指针。进行内存管理。在显式空闲链表中。可以采用后进先出的顺序维护链表,将最新释放的块放置在链表的开始处,也可以采用按照地址顺序来维护链表,其中链表中每个块的地址都小于它的后继地址,在这种情况下,释放一个块需要线性时间的搜索来定位合适的前驱。
7.10本章小结
本章主要介绍了hello 的存储器地址空间、段式管理、页式管理, VA 到PA 的变换、物理内存访问,fork、execve 时的内存映射、缺页故障与缺页中断处理、动态存储分配管理的相关内容。
第8章 hello的IO管理
8.1 Linux的IO设备管理方法
Linux中所有的IO设备都被模型化为文件,而所有的输入和输出都被当做对相应文件的读和写来执行。这种将设备映射为文件的方式,允许Linux内核引出一个简单、低级的应用接口,称为Unix I/O。这使得所有的输入和输出都能以一种统一且一致的方式来执行:打开文件、改变当前的文件位置、读写文件、关闭文件。
设备的模型化:文件
设备管理:unix io接口
8.2 简述Unix IO接口及其函数
Unix IO接口:Linux内核引出一个简单、低级的应用接口,称为Unix I/O。这使得所有的输入和输出都能以一种统一且一致的方式来执行
函数:
open和close - 打开和关闭文件
read 和 write – 最简单的读写函数;
readn 和 writen – 原子性读写操作;
iseek函数:修改文件偏移量
8.3 printf的实现分析
printf主函数:
调用的vsprintf函数:vsprintf的作用就是格式化。它接受确定输出格式的格式字符串fmt。用格式字符串对个数变化的参数进行格式化,产生格式化输出。返回的是要打印出来的字符串的长度
最后的write函数即为写操作,把buf中的i个元素的值写到终端。
write:
mov eax, _NR_write
mov ebx, [esp + 4]
mov ecx, [esp + 8]
int INT_VECTOR_SYS_CALL
从vsprintf生成显示信息,到write系统函数,到陷阱-系统调用 int 0x80或syscall等.
字符显示驱动子程序:从ASCII到字模库到显示vram(存储每一个点的RGB颜色信息)。
显示芯片按照刷新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点(RGB分量)。
8.4 getchar的实现分析
getchar函数:
在getchar函数中,首先声明了几个静态变量:buf表示缓冲区,BUFSIZ为缓冲区的最大长度,而bb指针指向缓冲区的首地址。
getchar调用read函数,将缓冲区读入到buf中,并将长度送给n,再重新令bb指针指向buf。最后返回buf中的第一个字符(如果长度n < 0,则报EOF错误)。
异步异常-键盘中断的处理:键盘中断处理子程序。接受按键扫描码转成ascii码,保存到系统的键盘缓冲区。
getchar等调用read系统函数,通过系统调用读取按键ascii码,直到接受到回车键才返回。
8.5本章小结
本章通过介绍hello中包含的函数所对应的unix I/O,以及printf和getchar函数的实现
结论
用计算机系统的语言,逐条总结hello所经历的过程。
- hello.c程序被创建后存储在内存中
- 然后预处理器将hello.c预处理成为hello.i,
- 接着编译器将hello.i翻译成汇编语言文件hello.s
- 汇编器将hello.s汇编成可重定位二进制代码hello.o
- 链接器将外部文件和hello.o连接起来形成可执行二进制文件hello
- shell通过fork和execve创建进程,然后把hello加载到其中,shell创建新的内存区域,并加载代码、数据和堆栈
- hello在执行的过程中遇到异常,会接受shell的信号完成处理
- hello在执行的过程中需要使用内存,那么就通过CPU和虚拟空间进行地址访问
- hello执行结束后,shell回收其僵死进程,从系统中消失
你对计算机系统的设计与实现的深切感悟,你的创新理念,如新的设计与实现方法。
计算机系统设计是一个复杂但是完备的过程,它确保程序运行的稳定性及准确性,它不仅仅是硬件和软件的结合,更是对计算机科学原理、算法、数据结构、操作系统、编程语言等多个领域深入理解的体现。
附件
列出所有的中间产物的文件名,并予以说明起作用。
参考文献
为完成本次大作业你翻阅的书籍与网站等
[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.
(参考文献0分,缺失 -1分)