计算机系统大作业

计算机系统

大作业

题     目  程序人生-Hellos P2P  

专       业          计算机              

学     号                        

班   级                        

学       生                   

指 导 教 师                     

计算机科学与技术学院

2021年5月

摘  要

本次实验通过完成hello.c文件的预处理、编译、汇编和链接,使他成为一个可执行文件,通过运用gdb,objdump等工具在linux下更好的理解了相关过程,也加深了对本门课的理解

关键词:计算机系统;hello;预处理;编译;汇编;链接;进程;虚拟内存;I/O                            

目  录

第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简介

Hello.c通过预处理、编译、汇编、链接过程生成了一个可执行文件hello,在shell中运行使他从program变成process,随后通过IO输出,结束进程,这就是O2O的全过程

1.2 环境与工具

硬件环境:X64CPU; 16GB RAM;512G HD

软件环境:Windows10 64位;VMware;Ubuntu;

使用工具:Codeblocks;objdump;edb

1.3 中间结果

hello.i 预处理后文件

hello.s 编译后文件

hello.o 汇编后文件

Hello 链接后的可执行文件

hello.elf hello的elf文件

hello.txt hello.o反汇编文件

helloasm.txt hello的反汇编文件

1.4 本章小结

本章主要介绍了这次作业的主要内容,开发环境,使用的工具,以及中间结果。


第2章 预处理

2.1 预处理的概念与作用

预处理的目的在于为下一步的汇编做准备。在C语言中,各种以#开头的编译指令,都被称为预处理命令。预处理命令属于C语言编译器,而不是C语言的组成部分。通过预处理命令可扩展C语言程序设计的环境。

预编译的主要作用如下:

  1. 将源文件中以”include”格式包含的文件复制到编译的源文件中。
  2. 用实际值替换用“#define”定义的字符串。
  3. 根据“#if”后面的条件决定需要编译的代码。

2.2在Ubuntu下预处理的命令

通过gcc -m64 -no-pie -fno-PIC -E -o hello.i hello.c命令就能得到预处理后的hello.i文件。

2.3 Hello的预处理结果解析

我门阅读hello.c和hello.i文件可见,虽然hello.c中的文件只有寥寥几十行,可是预处理后得到的hello.i文件却又几千行,这是因为预处理原文件中的宏进行了宏展开即将原来调用的库函数进行了展开,并且新hello.i程序中已经没有#include某个库这样的语句了。且生成的.i文件还是c语言且是文本文件。

2.4 本章小结

本章对预处理的过程进行了讨论,并在虚拟机上实现了他,得到了hello.i文件,还对这个过程进行了分析,有了深入的了解。


第3章 编译

3.1 编译的概念与作用

编译是将预处理后的文件进行翻译,将他翻译成一个汇编语言的程序。

编译的基本功能是把高级语言翻译成汇编语言,除此之外,编译还具备语法检查、调试措施、修改手段、覆盖处理、目标程序优化、不同语言合用以及人机联系等重要功能。

3.2 在Ubuntu下编译的命令

通过gcc -m64 -no-pie -fno-PIC -S -o hello.s hello.i指令就能得到一个hello.s的编译后的程序

3.3 Hello的编译结果解析

3.3.1:数据

  1. 常量:常量在汇汇编语言中变现为立即数
  2. 局部变量:局部变量存在在栈中
  3. 表达式:表达式存在在一个特定的地址里

3.3.2:赋值

i=0这样的句子,只用了mov系列的语句进行传送

3.3.3:sizeof:

i,argc均为int类型大小为4字节,argv为指针类型大小8字节

3.3.4:算术操作

使用add操作进行加法,sub进行减法等等...

3.3.5:逻辑运算

使用SAL、SHL来实现逻辑左移和算术左移,add来实现与,or来实现或等等...

3.3.6:关系操作:

使用cmp相关指令进行比较,比较结束之还可以通过ja、je等指令进行跳转。

3.3.6:数组、指针、结构体

他们的储存采用的是保存头指针的地址,然后通过偏移来实现所有数组的表示。

3.3.6:函数的调用

首先将调用的函数所需要的参数储存到栈中,然后调用函数,最后函数的结果再返回到栈中。

3.4 本章小结

本章讲述了什么是编译,以及有关汇编语言的一些知识,我们需要能够读懂汇编语言,并能够从汇编语言层面来思考问题,这样才能把问题理解的更加透彻,对编程也会有更加深入的理解。


第4章 汇编

4.1 汇编的概念与作用

汇编是将编译后的文件进行翻译,生成机器语言的过程,并将翻译好的机器语言储存再hello.o文件中,这个文件直接打开是无法阅读的,你只会看到一堆乱码。

4.2 在Ubuntu下汇编的命令

使用指令gcc -m64 -no-pie -fno-PIC -c -o hello.o hello.s即可得到汇编后的文件。

4.3 可重定位目标elf格式

使用readelf -all hello.o查看所有信息

ELF头以一个16字节的序列开始,这个序列描述了生成该文件的系统的字的大小和字节顺序。ELF头剩下的部分包含帮助链接器语法分析和解释目标文件的信息。其中包括ELF头的大小、目标文件的类型(如可重定位、可执行或者共享的)、机器类型(如x86-64)、 节头部表(section header table)的文件偏移,以及节头部表中条目的大小和数量。

重定位节的信息首先整个重定位位于hello.o二进制文件偏移量为0x340的位置上,其每个重定位信息给予了相对首地址的偏移量,通过info提供了重定位信息。在hello中需要重定位的信息有puts,exit,printf,sleepsecs,sleep,getchar 以及rodata。

4.4 Hello.o的结果解析

利用objdump -d -r hello.o对hello.c进行反汇编得到反汇编代码

使用objdump进行反汇编得到的内容与第三章编译中得到的hello.s进行对比可以发现:(1)反汇编结果中,除了右侧的汇编语言,左侧增加了由操作码和操作数组成的机器指令。通常机器指令的第一个数码为操作码,后续的数码为操作数。(2)操作数由十进制转换为十六进制(由0x开头)(3)每条机器指令有了对应的地址,而不是像hello.s中使用.L1和.L2等诸如此类的节来表示。(4)进行跳转时,通过跳转至某一特定的地址实现,而并非像hello.s中用.L1和.L2等诸如此类的节来作为跳转的标识(5)对可重定位的条目进行标识,此时尚未进行链接,机器码中用来表示符号引用的地址处均被设置为0,将在链接过程中进行补齐。

4.5 本章小结

本章对汇编的过程进行了讨论,通过readlf工具对可重定位文件进行了查看,解读了他的内容,还通过objdump查看了反汇编代码,对比了他和之前的汇编语言的区别


5链接

5.1 链接的概念与作用

链接是将各种代码和数据片段收集并组合成一个单一文件的过程,这个文件可以被加载到内存中并被执行。

作用:使分离编译成为可能

5.2 在Ubuntu下链接的命令

使用命令gcc -m64 -no-pie -fno-PIC -o hello.out hello.o

5.3 可执行目标文件hello的格式

    使用指令readelf -S hello查看hello的ELF格式的节头,如下图所示。从中可以得到各段的基本信息.

ELF是一个以16字节的一个序列开始,这个序列描述了文件大小和字节顺序,剩下部分帮助分析和解读文件的信息。

5.4 hello的虚拟地址空间

使用edb加载hello,查看本进程的虚拟地址空间各段信息,程序加载从0x401000开始存放

通过查看plugins->symbolViewer,与5.3对照可以发现他们使完全一样的

5.5 链接的重定位过程分析

使用命令objdump -d -r hello.o对hello.o可执行文件进行反汇编

对比发现,他最左侧的地址发生了变化,而其他的信息如原来调用的库等都被保留的下来,重新定位的部分也被真实的偏移量所填充。

5.6 hello的执行流程

执行流程如下:

ld-2.27.so!_dl_start ld-2.27.so!_dl_init hello!_start

libc-2.27.so!__libc_start_main

-libc-2.27.so!__cxa_atexit

-libc-2.27.so!__libc_csu_init hello!_init libc-2.27.so!_setjmp

-libc-2.27.so!_sigsetjmp

–libc-2.27.so!__sigjmp_save hello!main hello!puts@plt hello!exit@plt

*hello!printf@plt

*hello!sleep@plt

*hello!getchar@plt ld-2.27.so!_dl_runtime_resolve_xsave

-ld-2.27.so!_dl_fixup

–ld-2.27.so!_dl_lookup_symbol_x libc-2.27.so!exit

5.7 Hello的动态链接分析

   为了分析hello的动态链接过程,需要重点关注所加载的符号中的_GLOBAL_OFFSET_TABLE这一项。查看Loaded Symbols发现,该项的地址位于0x404000处,因此edb一加载hello可知行文件使用Data Dump观察这个地址上的内容。在调用dl_init之前时,Data Dump中该地址处部分信息缺失,如下图所示。

5.8 本章小结

本章讲述了hello.o链接生成hello.out的过程,我们需要了解可从定位文件hello的反汇编与可执行文件hello汇编代码的区别尤其是可重定位的部分,同时要了解main函数执行前后,一些其他函数的调用还使用edb对hello的执行进行了查看,对链接过程的实现进行了分析。


6hello进程管理

6.1 进程的概念与作用

进程就是一个执行中的程序,系统中每个程序的进程都在某个进程的上下文中,在进程运行时会提供两个假象,一个是好像每个程序都是独占处理器和内存的,另一个是程序中的代码和数据好像是系统内存中唯一的对象。

6.2 简述壳Shell-bash的作用与处理流程

Shell是一个交互型的应用级程序,它代表用户运行其他程序,bash是shell的一个变种。

Shell的基本功能是解释并运行用户的指令,重复如下处理过程:

(1)终端进程读取用户由键盘输入的命令行。

(2)分析命令行字符串,获取命令行参数,并构造传递给execve的argv向量

(3)检查第一个(首个、第0个)命令行参数是否是一个内置的shell命令

(3)如果不是内部命令,调用fork( )创建新进程/子进程

(4)在子进程中,用步骤2获取的参数,调用execve( )执行指定程序。

(5)如果用户没要求后台运行(命令末尾没有&号)否则shell使用waitpid(或wait…)等待作业终止后返回。

(6)如果用户要求后台运行(如果命令末尾有&号),则shell返回;

6.3 Hello的fork进程创建过程

父进程通过调用fork函数创建一个新的运行的子进程。新创建的子进程几乎但不完全与父进程相同。子进程得到与父进程相同但是独立的用户级虚拟地址空间副本,包括代码和数据段、堆、共享库以及用户栈。同时,子进程还获得与父进程任何打开文件描述符相同的副本。

注意,父进程和子进程之间的最大的区别在于它们有不同的PID。因此函数调用一次,会有两次返回。

6.4 Hello的execve过程

Execve函数在当前进程的上下文中加载并运行一个新的程序。Execve加载并运行可执行目标文件filename,且带参数列表argv和环境变量envp。只有当出现错误时,例如找不到filename,execve才会返回到调用程序。所以与fork调用一次返回两次不一样,execve调用一次并且从不返回。

6.5 Hello的进程执行

进程执行时,首先将寄存器的当前值保存到内存然后调度下一个进程执行,然后加载保存的寄存器,并进行上下文转换,就能完成调度,重复操作,知道程序执行结束。

6.6 hello的异常与信号处理

hello执行过程中会出现:(1)终止:会产生SIGINT信号,程序的运行被终止(2)中断:会产生SIGSTP信号,程序的运行被挂起。
执行hello程序,在程序的运行过程中ctrl + z将进程挂起,如下图所示。

运行ps,如下图所示

运行jobs

运行pstree

运行fg,进程收到SIGCONT信号,继续运行

运行kill -9 2813,发送SIGKILL信号给指定的pid杀死指定的进程

6.7本章小结

本章节中主要对运行hello后的进程展开讨论,并简单地回顾了进程fork过程、exceve过程和进程的私有地址空间等内容。通过在终端中运行hello并输入相关的指令,对进程的异常与信号处理部分的相关内容也有了更深入的理解。


7hello的存储管理

7.1 hello的存储器地址空间

(1)逻辑地址:是指由程式产生的和段相关的偏移地址部分

(2)线性地址:是逻辑地址到物理地址变换之间的中间层

(3)虚拟地址:是指计算机呈现出要比实际拥有的内存大得多的内存量。

(4)物理地址:是指出目前CPU外部地址总线上的寻址物理内存的地址信号,是地址变换的最终结果地址。

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

在实模式下,逻辑地址CS: EA所转换得到的物理地址为CS * 16 + EA。在保护模式下,以段描述符作为下标,到GDT/LDT表中查表获得短地址,将段地址加上偏移地址,得到线性地址,完成转换。

7.3 Hello的线性地址到物理地址的变换-页式管理

虚拟内容被组织为一个由存放在磁盘上的N个连续的字节大小的单元组成的数组。每个字节都有一个唯一的虚拟地址,作为数组的索引。磁盘上数组的内容被缓存在主存中。这些数据在缓存时被分割成块,作为磁盘和主存(较高层)之间的传输单元。虚拟内存系统通过将虚拟内存分割为大小固定的“虚拟页”来处理这个问题。同时物理内存也被分割为大小等同与虚拟页的“物理页”,并与“虚拟页”之间建立映射关系。从而达到由线性地址(虚拟地址)到物理地址的变换。

7.4 TLB与四级页表支持下的VA到PA的变换

实际系统中计算机采用TLB与四级页表来进行优化。首先我们还是得到n位的虚拟地址,这里以64位系统为例,目前的虚拟地址是48位,即n=48.

还是将这48位虚拟地址分为两部分,36位的虚拟页号和12位的页面偏移。

根据这36位的虚拟页号首先去TLB中查找。TLB是虚拟寻址的缓存,每一行都保存着一个页表条目PTE。由于TLB是高度组相联cache,将虚拟页号VPN拆分成两部分:32位的TLBT和4位的TLBI进行TLB中的索引。根据4位的TLBI确定TLB中的组号,再根据TLBT进行组中每一行的比较。如果对应页表条目在TLB中命中,则可以直接从TLB中读取页表条目,得到页表条目中的物理页号,将其与12位的页面偏移相组合即得到物理地址。

如果在TLB中页表条目未命中,则仍需要访问主存中的页表,只不过计算机采用了4级页表来对页表进行压缩。这里仍需要对虚拟页号VPN进行分割,只不过这里的分割方法又有些不同,将其分为4部分,每一部分都是9个字节单独作为每一级页表的虚拟页号,如高9位可以作为1级页表的虚拟页号,低9位作为4级页表的虚拟页号。1-3级页表中的页表条目每一个页表条目存放一个下一级页表的基址,如1级页表中的第3个页表条目可能存放着第三个2级页表的基址。最终的第四级页表中的页表条目则存放着虚拟页面所映射的物理页号。这样,首先通过CR3获得第一个页表的基址,再通过4个VPN,每一个VPN对应着一个该级页表的虚拟页号,1级页表VPN确定一个条目,确定读取哪一个二级页表,再结合二级页表的VPN读取二级页表条目···以此类推,可从某一个四级页表中得到对应的物理页号,将其与12位的页面偏移结合即可得到物理地址。地址翻译示意图如下:

7.5 三级Cache支持下的物理内存访问

对于每一级cache来说,将上述过程所得的物理地址分为高速缓存标记(CT)、高速缓存索引(CI)、缓存块内的字节偏移量(CO)三个部分,利用索引位找到所在组,再对比标记位,若相等且标志位为1则说明命中,则取结果给CPU,若不命中则继续去二级、三级cache中查找。

7.6 hello进程fork时的内存映射

当fork函数被当前进程调用时,内核为新进程创建各种数据结构,并分配给它一个唯一的PID。为了给这个新进程创建虚拟内存,它创建了当前进程的 mm_struct、区域结构和页表的原样副本。它将两个进程中的每个页面都标记为只读,并将两个进程中的每个区域结构都标记为私有的写时复制。

当fork在新进程中返回时,新进程现在的虚拟内存刚好和调用fork时存在的虚拟内存相同。当这两个进程中的任一个后来进行写操作时,写时复制机制就会创建新页面,因此,也就为每个进程保持了私有地址空间的抽象概念。

7.7 hello进程execve时的内存映射

函数execve在当前进程中加载并运行包含在可知行目标文件a.out中的程序,用a.out程序有效地替代了当前程序。加载并运行需要以下几个步骤:(1)删除已存在的用户区域(2)映射私有区域(3)映射共享区域(4)设置程序计数器

7.8 缺页故障与缺页中断处理

  1. 处理器将虚拟地址发送给 MMU
  2. MMU 使用内存中的页表生成PTE地址
  3. 有效位为零, 因此 MMU 触发缺页异常
  4. 缺页处理程序确定物理内存中牺牲页 (若页面被修改,则换出到磁盘)
  5. 缺页处理程序调入新的页面,并更新内存中的PTE
  6. 缺页处理程序返回到原来进程,再次执行缺页的指令

7.9动态存储分配管理

(1)分配器的类型

显式分配器: 要求应用显式地释放任何已分配的快

例如,C语言中的 malloc 和 free

隐式分配器: 应用检测到已分配块不再被程序所使用,就释放这个块

比如Java,ML和Lisp等高级语言中的垃圾收集

(2)记录空闲块的组织结构

方法 1:隐式空闲链表 (Implicit list) 通过头部中的大小字段—隐含地连接所有块

方法 2: 显式空闲链表 (Explicit list) 在空闲块中使用指针指向前后空闲块

方法 3: 分离的空闲列表 (Segregated free list)按照大小分类,构成不同大小的空闲链表

方法 4: 按块按大小排序—平衡树

在每个空闲块中使用一个带指针的平衡树,并使用长度作为权值

7.10本章小结

本章讲述了hello的储存管理,我们需理解逻辑地址、线性地址、虚拟地址与物理地址之间的关系与转换方法。同时要理解快表与高速缓存的思想是基本一致的,最后对动态存储分配管理的各种方法要十分了解。


8hello的IO管理

8.1 Linux的IO设备管理方法

设备的模型化:文件。文件的类型有如下几种:(1)普通文件,包含任意数据的文件(2)目录,包含一组链接的文件,每个链接都将一个文件名映射到一个文件(3)套接字,用来与另一个进程进行跨网络通信的文件(4)命名通道(5)符号链接(6)字符和块设备。

设备管理:unix io接口,具有如下的几个作用:(1)打开和关闭文件(2)读取和写入文件(3)改变当前文件的位置

8.2 简述Unix IO接口及其函数

(1)函数原型:int open(char * filename, int flags, mode_t mode);

解析:返回值是一个文件描述符:filename顾名思义就是文件名,flage文件是打开方式,第三个形参应用于创建文件时使用。若出错都返回-1

(2)函数原型:int close(int fd);

解析:关闭一个打开的文件,若关闭一个已关闭的文件的描述符会出错。

(3)函数原型:ssize_t read(int fd ,void* buf ,size_t n);

解析:read函数从描述符为fd 的当前文件位置复制最多n个字节到内存位置buf。返回值一1表示一个错误,而返回值0表示EOF。否则,返回值表示的是实际传送的字节数量。

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

解析:write函数从内存位置buf复制至多n个字节到描述符fd的当前文件位置。

8.3 printf的实现分析

函数printf实现的内部过程中调用了vsprintf和write函数,接受一个格式串之后将匹配到的参数按照格式串的形式输出。在第三章解读汇编语言时就曾提到过这一点,调用printf函数之前除了要将累加器%rax设置为0之外,向printf函数传入的第一个参数%rdi就是所谓的“格式串”,如%s、%d等等。这些格式串如同全局变量一般存放于.rodata节当中。

从vsprintf生成显示信息,到write系统函数,到陷阱-系统调用 int 0x80或syscall。字符显示驱动子程序:从ASCII到字模库到显示vram(存储每一个点的RGB颜色信息)。显示芯片按照刷新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点(RGB分量)。

8.4 getchar的实现分析

函数getchar在具体实现的过程内部将会调用read函数,将整个缓冲区都读到了buf里面,然后将返回值是缓冲区的长度。但是只有buf长度为0,getchar才会调用read函数,否则是直接将保存的buf中的最前面的元素返回。

异步异常-键盘中断的处理:键盘中断处理子程序。接受按键扫描码转成ascii码,保存到系统的键盘缓冲区。getchar等调用read系统函数,通过系统调用读取按键ascii码,直到接受到回车键才返回。

8.5本章小结

本章讲述了hello的IO管理,我们应了解Unix IO接口及其函数,并且理解各种基本函数的实现,例如:printf和getchar。

结论

最后,对hello一生中所经历的过程逐条进行总结:

(1)编写源程序hello.c

(2)hello.c进行预处理生成hello.i,可以在hello.i中找到外部文件帮助它的痕迹

(3)hello.i编译生成hello.s,其中的内容被编译为汇编语言

(4)hello.s汇编生成hello.o,其中汇编语言逐条转换为机器语言

(5)hello.o终于链接生成了可执行目标文件hello

(6)在linux下的终端中运行hello

(7)shell中调用fork函数创建子进程,并调用execve函数加载并运行hello

(8)hello似乎还挺强大的,似乎能够独占地使用CPU和内存系统

(9)在运行过程中收到信号,hello进程必须做出相应的反应,可能这就是被生活逼的喘不过气来的样子吧

(10)直到收到SIGINT信号,进程终止。从此以后,hello再也不动了,被shell父进程回收子进程。

虽然hello程序简简单单,但是其中的知识却远远多于他表面展示给我们的,正式这简简单单的hello程序,让我更加深刻的了解了一个程序的一生,对他们有了更多的敬畏


附件

hello.c 源程序(文本文件)
hello.i 修改了的源程序(文本文件)
hello.s 汇编程序(文本文件)
hello.o 可重定位目标程序(二进制)
hello.out 可执行目标程序(二进制)


参考文献

为完成本次大作业你翻阅的书籍与网站等

[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.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值