计算机系统
大作业
题 目 程序人生-Hello’s P2P
专 业 物联网工程
学 号 2022112820
班 级 2237301
学 生 孟宇航
指 导 教 师 吴 锐
计算机科学与技术学院
2024年5月
摘要是论文内容的高度概括,应具有独立性和自含性,即不阅读论文的全文,就能获得必要的信息。摘要应包括本论文的目的、主要内容、方法、成果及其理论与实际意义。摘要中不宜使用公式、结构式、图表和非公知公用的符号与术语,不标注引用文献编号,同时避免将摘要写成目录式的内容介绍。
关键词:关键词1;关键词2;……;
(摘要0分,缺失-1分,根据内容精彩称都酌情加分0-1分)
目 录
第1章 概述
1.1 Hello简介
① P2P(From Program to Process)过程:
hello的生命周期是从一个高级C语言程序开始的,分为四个阶段:首先经过预处理器cpp进行预处理,生成文本文件hello.i,然后经过编译器ccl生成hello.s汇编程序,接着经过汇编器as生成hello.o文件,最后经过链接器ld将其与引用到的库函数链接,生成可执行文件hello。再通过系统创建一个新进程并且把程序内容加载,实现有程序到进程的转化。
② O2O(From Zero-0 to Zero-0)过程:
当程序员在shell中运行可执行目标文件hello时,shell识别出这是一个外部命令,先调用 fork函数创建了一个新的子进程(Process),然后调用execve函数在新的子进程中加载并运行hello。运行hello还需要CPU为hello分配内存、时间片。在hello运行的过程中,CPU要访问相关数据需要MMU的虚拟地址到物理地址的转化,其中 TLB和四级页表为提高地址翻译的速度做出了巨大贡献,得到物理地址后三级 Cache又帮助CPU快速得到需要的字节。系统的进程管理帮助hello切换上下文、shell的信号处理程序使得hello在运行过程中可以处理各种信号,当程序员主动地按下Ctrl+Z或者hello运行到“return 0”;时hello所在进程将被杀死,shell会回收它的僵死进程。
1.2 环境与工具
列出你为编写本论文,折腾Hello的整个过程中,使用的软硬件环境,以及开发与调试工具。
硬件环境:X64 CPU;2GHz;2G RAM;256GHD Disk以上;
软件环境:Windows10 64位; Vmware 11; Ubuntu 16.04 LTS 64位;
开发工具:CodeBlocks;vi/vim/gpedit+gcc;gdb;edb;readelf;objdump等。
1.3 中间结果
列出你为编写本论文,生成的中间结果文件的名字,文件的作用等。
得到的中间文件:
hello.i :hello.c预处理器(cpp)预处理得到修改了的源程序
hello.s :hello.i编译器(cc1)翻译成汇编程序
hello.o :hello.s汇编器(as)成为可重定位目标程序(二进制)
hello :连接器(ld)调用printf.o得到可执行目标程序(二进制)
hello.elf :hello.o的elf格式文件
helloo.elf :hello的elf格式文件
1.4 本章小结
本章通过简单介绍hello.c程序一生中的P2P过程和020过程,展示了一个源程序是如何经过预处理、编译、汇编、链接等阶段,生成各种各样的中间文件,最终成为一个可执行目标文件的。
(第1章0.5分)
第2章 预处理
2.1 预处理的概念与作用
以字符#开头的命令,修改原始的C程序,语言提供的编译预处理功能主要有三种:宏定义、文件包含和条件编译。预处理功能便于程序的修改、阅读、移植和调试,也便于实现模块化程序设计
2.2在Ubuntu下预处理的命令
gcc –E hello.c –o hello.i
2.3 Hello的预处理结果解析
hello.i文件中将#include进行了展开,包含了对文件的引用
hello.i中对数据类型用typedef进行了替换
hello.i对内部函数进行了封装
hello.i文件最后部分展示了代码
2.4 本章小结
本章介绍了预处理的概念和作用,以及预处理的指令,随后分析了预处理的过程与结果。通过本章的学习,了解到C 语言预处理一般由预处理器(cpp)进行.
(第2章0.5分)
第3章 编译
3.1 编译的概念与作用
编译就是文件hello.i通过编译器(ccl)生成hello.s的过程,在编译过程中,会进行词法分析,语法分析,语义分析、中间代码生成、代码优化、目标代码生成来生成汇编语言程序,使代码变成机器易于理解的形式。
3.2 在Ubuntu下编译的命令
gcc -S hello.i -o hello.s
3.3 Hello的编译结果解析
主体部分如上图:
3.3.1对局部变量
进入main后,会向栈申请一段空间用于储存局部变量(如图中21——23),21行将栈指针(rsp)减少32,22、23分别将edi、rsi中数据存于这段空间中。
3.3.2 对循环
如图中24、25行,当24行cmp的结果为0时,25行进行跳转,跳转至.L2。
3.3.3 对函数引用
如图中28行,使用call引用puts函数,并在返回时利用ret返回。
3.3.4 对赋值
如图中19行,用move将源操作数(rsp)的值付给被操作数(rbp)。
3.3.5 对加减运算
如图中21、36行,使用sub指令使两数相减(rsp-32),add指令使两数相加。
3.4 本章小结
本章主要介绍了编译的概念以及过程。编译程序所做的工作,就是通过词法分析和语法分析,在确认所有的指令都符合语法规则之后,将其翻译成等价的中间代码表示或汇编代码表示。同时通过示例函数表现了C语言如何转换成为汇编代码。介绍了汇编代码如何实现数据、赋值、算术操作、关系操作、控制转移、函数调用、数组操作。
(第3章2分)
第4章 汇编
4.1 汇编的概念与作用
汇编就是文件hello.s通过汇编器(as)生成hello.o的过程,在汇编过程中,汇编器会将文件转换为二进制文件——可重定位目标文件。
4.2 在Ubuntu下汇编的命令
gcc -C hello.s -o hello.o
4.3 可重定位目标elf格式
开头是elf头,包含文件类型、节头表偏移等信息。
之后是节头表,包含了节数以及各节名称、类型、地址、偏移量、大小、全体大小、旗标、链接、信息、对齐等信息。
重定位节,包含.text节中需要重定位的信息。包含printf,atoi,getchar等。
符号表存放了引用的符号与函数信息。下图为部分符号表。
4.4 Hello.o的结果解析
(以下格式自行编排,编辑时删除)
反汇编代码:objdump -d -r hello.o
Main函数部分反汇编代码如图。反汇编代码与原.s文件相比,增加了相对应的机器语言的代码。
同时,在:
- 函数调用处有所不同:
- 进制方面有所不同
- 分支转移有所不同
在反汇编代码中,分支转移与函数调用时都加上了跳转的真实地址以便于下一步操作。
4.5 本章小结
本章介绍了汇编的概念和作用,接着通过实操,对hello.s文件进行汇编,生成ELF可重定位目标文件hello.o,并查看了hello.o的ELF头、节头表、可重定位信息和符号表等,最后反汇编得到的文件与第三章的.s文件作对比,是我们更清晰的了解汇编的作用。
(第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的格式
如上图,与之前相比,所链接文件的各节分别组合成26个段,并且在ELF头中增添了指令起始位置。
加载hello,查看虚拟空间各段信息。
由上可以看出该程序地址从0x401000开始,并可通过ELF头中的段偏移得知各段起始位置。
可执行文件对可重定位目标文件的重定位涉及符号解析、地址分配和地址调整。在链接过程中,各个可重定向文件的相同elf section会被聚合在一起形成可执行文件的对应段。链接器将所有目标文件的符号表合并,解析每个符号的定义和引用。每个目标文件包含重定位条目,指示哪些地址需要调整。链接器读取这些条目,确定需要更新的地址。所有代码和数据都能正确加载到内存中,并确保可执行文件能够正确执行。
5.6 hello的执行流程
<_init>:4004c0
<.plt>: 4004e0
<puts@plt>:4004f0
<puts@GLIBC_2.2.5> 4004f6
<printf@plt>: 400500:
<printf@GLIBC_2.2.5> 400506:
<getchar@plt>:400510
<getchar@GLIBC_2.2.5>400516
<atoi@plt>:400520
<atoi@GLIBC_2.2.5>400526
<exit@plt>:400530
<exit@GLIBC_2.2.5>400536
<sleep@plt>:400540
<sleep@GLIBC_2.2.5>400546:
<_start>: 400550
<__libc_start_main@GLIBC_2.2.5>40057a:
<_dl_relocate_static_pie>:400580
5.7 Hello的动态链接分析
调用前后,变化如图所示:
本章利用edb解析了链接的实现过程,包括动态链接、elf头等。
(第5章1分)
6.1 进程的概念与作用
进程的概念:进程是一个正在运行的程序的实例,包括程序的指令、数据、堆栈以及与操作系统相关的状态信息。进程是操作系统进行资源分配和保护的基本单位。
作用:
1.资源分配与管理:进程是操作系统进行资源分配的基本单位,包括CPU时间、内存空间、I/O设备等。操作系统通过调度算法来决定哪个进程获得CPU使用权。
2.并发执行:进程使得多个程序可以同时运行(并发或并行),提高了系统的利用率和响应速度。现代操作系统使用多任务处理来实现进程的并发执行。
6.2 简述壳Shell-bash的作用与处理流程
1.作用:Shell 作为命令解释器,接受用户输入的命令,并将其翻译为操作系统能够执行的动作。同时,Shell 提供了一个交互式的用户接口,可以启动和管理进程,支持后台运行、进程间通信、管道等功能,用户可以通过命令行直接与操作系统进行交互。这种接口对系统管理和开发工作非常重要。
2.处理流程:显示提示符——>读取命令——>解析命令(语法、词汇解析)——>执行命令——>等待进程结束——>(处理输出和错误)——>信号处理
6.3 Hello的fork进程创建过程
1.调用 fork:
当一个进程调用 fork 时,操作系统会创建一个新进程,该新进程是调用进程的副本。这个新进程称为子进程,调用 fork 的进程称为父进程。
2.复制进程上下文:
操作系统为子进程分配一个新的进程控制块(PCB),并复制父进程的上下文到新的 PCB 中。这包括:
进程标识符(PID):子进程获得一个新的、唯一的 PID。
进程状态:包括寄存器内容、程序计数器(PC)、堆栈指针等。
内存映像:包括代码段、数据段、堆和栈。子进程的内存空间是父进程内存空间的副本,但在现代操作系统中通常使用写时复制(Copy-On-Write, COW)技术来提高效率。
文件描述符表:父进程打开的所有文件描述符会被子进程共享,但文件指针是独立的。
3.返回两次:
fork 系统调用会返回两次:一次在父进程中,返回子进程的 PID;一次在子进程中,返回 0。
通过检查 fork 的返回值,进程可以确定自己是父进程还是子进程,并执行不同的代码路径。
6.4 Hello的execve过程
调用 execve:
当一个进程调用 execve 时,它指定要执行的程序的路径、命令行参数和环境变量。
加载新程序:
操作系统读取并解析指定程序的可执行文件。通常,这个文件是一个二进制可执行文件,包含程序的代码、数据和其他必要的信息。
操作系统会从文件系统中读取该可执行文件的内容,并将其加载到当前进程的地址空间。
替换地址空间:
当前进程的地址空间被完全替换为新程序的地址空间。这包括:
代码段:新的可执行文件中的代码段取代旧程序的代码段。
数据段:新的可执行文件中的数据段取代旧程序的数据段。
堆和栈:新的堆和栈段被重新初始化,与新程序的需求相符。
所有旧的内存映射、堆栈、堆和其他地址空间内容都被丢弃。
初始化新程序:
新程序的初始化代码被执行。通常,这包括设置命令行参数 (argv) 和环境变量 (envp)。
程序的入口点(通常是 main 函数)开始执行。
返回值:
如果 execve 成功,新的程序开始执行,原始的程序代码不再执行,所以 execve 调用不会返回。
如果 execve 失败,例如由于找不到指定的可执行文件或权限问题,它将返回 -1,并设置 errno 以指示错误。
6.5 Hello的进程执行
编译:然后,程序被编译成机器代码,这是计算机可以直接执行的指令。
加载到内存:接下来,操作系统使用execve()或fork()系统调用将编译后的程序加载到内存中。如果使用fork(),会创建一个新的进程;如果使用execve(),则会替换当前进程的映像。
进程调度:操作系统根据进程的状态(如运行中、等待I/O操作、休眠等)和调度策略,决定哪个进程应该获得CPU时间片。
执行:获得CPU时间片的进程开始执行。这通常意味着从程序的main函数开始执行。
输出:程序执行到输出语句(如printf()),操作系统将字符发送到相应的设备(如终端或显示器)。
退出:程序执行完毕后,操作系统会回收进程使用的资源(如内存、文件描述符等),并将控制权返回给操作系统。
6.6 hello的异常与信号处理
SIGINT:如图,用ctrl+c将SIGINT信号发送向前台的每个程序,中断其运行。
SIGTSTP:如图,用ctrl+z发送IGTSTP信号,将程序挂起,可再用fg信号继续该程序。
SIGKILL:使用kill -9 PID 杀死hello程序如图。
6.7本章小结
本章介绍了进程的概念,同时探讨了fork与execve进程的生成过程。最后探讨了hello在进程执行中遇到的异常与信号处理。
(第6章1分)
第7章 hello的存储管理
7.1 hello的存储器地址空间
逻辑地址:CPU生成的地址,可能包含段选择子和段内偏移量。
线性地址:段机制转换后的地址,即段基地址与段内偏移量之和。
虚拟地址:分页机制处理后的地址空间,程序员视角下的内存地址。CPU启动保护模式之后,程序运行在虚拟地址空间中,虚拟地址空间是所有可能地址的集合,对于一个64位的机器而言,则集合中共有2^64种可能。
物理地址:实际内存单元的地址,硬件内存芯片的地址。
7.2 Intel逻辑地址到线性地址的变换-段式管理
在 Intel 的段式内存管理中,逻辑地址到线性地址的转换过程如下:
1.从逻辑地址中提取段选择子和段内偏移量。
2.使用段选择子查找段描述符表(GDT 或 LDT),获取段描述符。
3.从段描述符中提取段基地址。
4.将段基地址与段内偏移量相加,得到线性地址。
7.3 Hello的线性地址到物理地址的变换-页式管理
在页式内存管理中,线性地址到物理地址的转换过程如下:
1.从线性地址中提取目录索引、页表索引和页内偏移量。
2.使用目录索引在页目录中查找对应的页表地址。
3.使用页表索引在页表中查找对应的页框地址。
4.将页框地址与页内偏移量相加,得到物理地址。
7.4 TLB与四级页表支持下的VA到PA的变换
1.TLB查找:检查TLB中是否有对应的页表项。
如果命中,直接得到物理地址。
如果未命中,进行四级页表查找。
2.四级页表查找:逐级从一级页表查找到四级页表,最终得到物理页框地址。
3.计算物理地址:将物理页框地址与页内偏移量相加,得到最终的物理地址。
7.5 三级Cache支持下的物理内存访问
三级缓存系统通过分层次结构,加速了数据的访问:
L1缓存:最快速,但容量最小,适合经常访问的数据。
L2缓存:速度适中,容纳更多数据,作为L1缓存的后备。
L3缓存:速度较慢,但容量最大,作为L2缓存的后备。
在每个缓存级别,访问过程都遵循类似的步骤:查找缓存,如果命中则返回数据,如果未命中则继续查找下一级缓存或最终访问主存。通过这种分层次的缓存结构,系统可以显著减少平均内存访问时间,提高整体性能。
7.6 hello进程fork时的内存映射
fork 系统调用创建子进程时,采用写时复制机制,避免了不必要的内存复制,提高了性能。父进程和子进程共享相同的物理内存页,直到某一方需要写入这些页,这时才会进行实际的页复制操作。这样提高了系统资源的利用效率,并减少了内存开销。
7.7 hello进程execve时的内存映射
execve 系统调用用于加载并执行一个新程序,它会清空当前进程的地址空间并用新程序的地址空间替代。这包括加载新程序的代码段、数据段、BSS段,以及初始化新的堆和栈,从而使得新程序可以从 main 函数开始执行。
7.8 缺页故障与缺页中断处理
过程:
1. 进程尝试访问某虚拟地址。
2. 发现该地址不在物理内存中,引发缺页故障。
3. 硬件触发缺页中断,操作系统中断处理程序开始执行。
4. 检查页面表,确定缺页地址。
5. 判断访问是否合法:
- 非法访问:向进程发送信号(如`SIGSEGV`)。
- 合法访问:继续处理。
6. 页换入:
- 找到空闲页框或进行页面置换。
- 从磁盘读取页面到物理内存。
7. 更新页面表和TLB。
8. 返回进程继续执行,引起缺页故障的指令重新执行。
7.9动态存储分配管理
分配内存:
- malloc(size_t size):分配 size 字节的内存,并返回指向已分配内存块的指针。如果分配失败,返回 NULL。
- calloc(size_t nmemb, size_t size):分配初始化为零的内存,分配 nmemb 个元素,每个元素大小为 size 字节。
3.realloc(void *ptr, size_t size):调整先前已分配内存块的大小,可能会移动数据到新的内存位置。
释放内存:
1.free(void *ptr):释放之前通过 malloc、calloc 或 realloc 分配的内存块。
动态内存管理的基本策略
分区空闲链表(Segregated Free Lists):
将不同大小的空闲块分别存储在不同的链表中,以加速分配和释放过程。这种方法将内存分块管理,避免了遍历长链表,提升了效率。
分裂与合并(Splitting and Coalescing):
当分配一个大的空闲块时,分裂它以满足请求,并保留剩余部分供将来使用。
当释放内存块时,尝试合并相邻的空闲块,减少碎片化。
动态内存管理的实现细节
7.10本章小结
本章介绍了hello的存储地址空间,intel的段式管理、hello的页式管理,以及在TLB和四级页表的支持下完成VA到PA的变换过程,三级Cache支持下的物理内存访问。解释了hello进程的fork与execve时的内存映射,缺页故障及其处理,以及进程的动态存储分配的管理。
(第7章 2分)
第8章 hello的IO管理
8.1 Linux的IO设备管理方法
(以下格式自行编排,编辑时删除)
1. 设备的模型化:文件
在Unix和类似的操作系统中,设备被抽象和模型化为文件。这种设计理念使得设备的操作与普通文件的操作一致,简化了用户和程序对设备的使用。
1.设备文件
设备文件是特殊的文件,位于 /dev 目录下,每个设备在这个目录中都有一个对应的文件。设备文件分为两类:
字符设备文件:用于按字符流处理数据的设备,如键盘和串口。
块设备文件:用于按数据块处理数据的设备,如硬盘和SSD。
2.统一接口
通过设备文件,用户可以使用标准的文件操作系统调用(如 open、read、write、close 等)对设备进行操作。这种统一的接口设计使得设备操作与普通文件操作一致,简化了编程模型。
2. 设备管理:Unix I/O接口
Linux提供了一系列标准的Unix I/O接口,用于对文件和设备进行操作。以下是一些关键的I/O系统调用及其作用:
基本I/O系统调用
open:打开文件或设备。通过指定路径和标志,返回一个文件描述符。
read:从文件或设备中读取数据。通过文件描述符读取指定数量的字节到缓冲区。
write:向文件或设备写入数据。通过文件描述符从缓冲区写入指定数量的字节。
close:关闭文件或设备。释放文件描述符和相关资源。
8.2 简述Unix IO接口及其函数
8.2.1Unix IO接口
Unix I/O接口为一种重要的系统编程基础,提供了一组用于文件和设备操作的系统调用,使程序可以进行文件读写、设备控制和数据传输。
8.2.2函数
1. open
功能:打开文件或设备,返回一个文件描述符。
返回值:成功时返回文件描述符,失败时返回 -1 并设置 errno。
2. read
功能:从文件或设备中读取数据。
返回值:成功时返回读取的字节数,失败时返回 -1 并设置 errno。
3. write
功能:向文件或设备写入数据。
返回值:成功时返回写入的字节数,失败时返回 -1 并设置 errno。
4. close
功能:关闭文件或设备。
返回值:成功时返回 0,失败时返回 -1 并设置 errno。
5. lseek
功能:在文件中移动文件偏移量(文件指针)。
返回值:成功时返回新的文件偏移量,失败时返回 -1 并设置 errno。
6. stat 和 fstat
功能:获取文件或设备的状态信息。
返回值:成功时返回 0,失败时返回 -1 并设置 errno。
7. ioctl
功能:设备控制操作。
返回值:成功时返回 0,失败时返回 -1 并设置 errno。
8.3 printf的实现分析
Printf函数:
Printf函数的代码中,va_list arg = (va_list)((char*)(&fmt) + 4)表示获取第一个参数(((char*)(&fmt指向第一个参数) + 4),这句代码目的是让argv指向第一个字符串;
第二句的作用是格式化,并返回要打印的字符串的长度;
第三句的作用是调用write函数将buf的前i个字符输出到终端,调用了unix I/O。
Vsprintf函数:
从vsprintf生成显示信息,到write系统函数,到陷阱-系统调用 int 0x80或syscall等.
字符显示驱动子程序:从ASCII到字模库到显示vram(存储每一个点的RGB颜色信息)。
显示芯片按照刷新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点(RGB分量)。
8.4 getchar的实现分析
Getchar函数:
异步异常-键盘中断的处理:键盘中断处理子程序。接受按键扫描码转成ascii码,保存到系统的键盘缓冲区。
getchar等调用read系统函数,通过系统调用读取按键ascii码,直到接受到回车键才返回。(当缓冲区非空时,不会调用read函数,而是简单的返回缓冲区最前面的元素。)
8.5本章小结
本章介绍了Linux的I/O设备的基本概念和管理方法,以及Unix I/O接口及其函数。最后分析了printf函数和getchar函数的工作过程。
(第8章1分)
结论
1. 编写源代码
编写:程序员使用文本编辑器编写C语言源代码,保存为一个.c文件。
工具:文本编辑器。
输出:C语言源文件。
2. 预处理
过程:预处理器将源代码中的预处理指令处理掉。
工具:预处理器(通常与编译器集成)。
输出:预处理后的源代码(通常仍是文本形式,但展开了所有的宏和头文件)。
3. 编译
过程:编译器将预处理后的源代码翻译成汇编代码。
工具:编译器。
输出:汇编代码文件。
4. 汇编
过程:汇编器将汇编代码转换成机器代码,生成目标文件。
工具:汇编器。
输出:目标文件,包含机器指令和数据,但尚未链接。
5. 链接
过程:链接器将一个或多个目标文件和库文件链接在一起,生成可执行文件。
工具:链接器。
输出:可执行文件。
6. 加载
过程:操作系统加载器将可执行文件从磁盘加载到内存中,准备执行。
工具:操作系统加载器。
输出:在内存中的可执行映像,准备执行。
7. 执行
过程:处理器开始执行加载到内存中的程序指令。
工具:处理器(CPU)。
输出:运行中的程序。程序在执行过程中可能会进行多种操作,如内存分配、I/O操作、系统调用等。
8. 终止
过程:程序执行完毕,或者被中断。操作系统回收程序使用的资源。
工具:操作系统。
输出:程序的最终输出结果(如显示在终端上的信息、生成的文件等),以及操作系统资源的回收。
感悟:
计算机系统是现代技术的奇迹,其复杂的层次结构从硬件到软件无缝协作,展现了人类智慧的结晶。从处理器的计算、内存的管理,到操作系统的调度,都体现了对计算高效性和可靠性的追求。通过学习计算机系统,我们理解了hello在计算机中从诞生至终止的历程,也对计算机本身从硬件到软件有了一个更深刻的理解。理解和掌握计算机系统,不仅是技术进步的关键,更是探索和创新的动力源泉。
(结论0分,缺失 -1分,根据内容酌情加分)
附件
列出所有的中间产物的文件名,并予以说明起作用。
1.hello.c:源程序
2.hello.i:预处理后的文本文件
3.hello.s:编译后的汇编文件
4.hello.o:汇编后的可重定位目标文件
5.hello:链接后的可执行目标文件
(附件0分,缺失 -1分)
参考文献
为完成本次大作业你翻阅的书籍与网站等
[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分)