哈工大2022计算机系统大作业
计算机系统
大作业
题 目 程序人生-Hello’s P2P
专 业 计算机
指 导 教 师 吴锐
计算机科学与技术学院
2021年5月
2.2在Ubuntu下预处理的命令............................................................................. - 5 -
5.3 可执行目标文件hello的格式........................................................................ - 8 -
6.2 简述壳Shell-bash的作用与处理流程........................................................ - 10 -
6.3 Hello的fork进程创建过程......................................................................... - 10 -
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 -
8.2 简述Unix IO接口及其函数.......................................................................... - 13 -
第1章 概述
1.1 Hello简介
P2P:即为program to process,从程序到进程。在Linux下,程序hello.c在经过cpp的预处理、ccl的编译、as的汇编、ld的链接后最终成为可执行目标程序hello,在shell中键入启动命令后,shell为其fork产生一个子进程,然后hello便从程序变为了进程。
020: shell为此子进程execve,将其映射到虚拟内存,进入程序入口后程序开始载入物理内存,然后进入 main函数执行目标代码,CPU为运行的hello分配时间片执行逻辑控制流。在程序运行结束后,shell父进程负责回收hello进程,内核删除相关数据结构。
1.2 环境与工具
硬件环境:X64 CPU;2GHz;2G RAM;256GHD Disk 以上
软件环境:Windows7 64位以上;VirtualBox/Vmware 11以上;Ubuntu 16.04 LTS 64位/优麒麟 64位
开发与调试工具:gcc,vim,edb,readelf,HexEdit等
1.3 中间结果
3.hello.s 预处理后的结果编译后的结果(汇编语言文本)
4.hello.o 编译后的结果链接后的可重定位目标文件(二进制)
1.4 本章小结
第2章 预处理
2.1 预处理的概念与作用
概念:预处理器cpp根据#开头的宏定义、条件编译等命令,修改原始c程序,将引用的库展开合并成一个完整的文本文件。
1.处理条件编译指令,将#ifdef、#else等指令进行处理,把某部分代码包含进来或排除在外,将不必要的代码过滤掉。
2.处理#define、#include等指令,把相应的定义和对应的头文件加入进来,使得编译程序对其处理。
3.处理一些特殊符号例如LINE、FILE等,用合适的值对其进行替换。
2.2在Ubuntu下预处理的命令
2.3 Hello的预处理结果解析
预处理删除了原来的程序主体段的注释信息,预处理删除了我们的注释信息(图2)除了注释部分以及头文件部分,预编译文件与源文件差别不大。
2.4 本章小结
本章主要介绍了预处理的相关概念和应用功能。分析hello.c预处理得到hello.i文本文件的过程,发现了预处理阶段的行为:头文件的展开、宏替换、去掉注释、条件编译。
第3章 编译
3.1 编译的概念与作用
将高级语言程序转化为机器可直接识别处理执行的的机器码的中间步骤。除了基本作用之外,编译程序还具备语法检查、调试措施、修改手段、覆盖处理、目标程序优化等重要功能。
3.2 在Ubuntu下编译的命令
3.3 Hello的编译结果解析
这里也是通过cmp和jx去实现if(argc!=4)的逻辑控制
文件中唯一的数组是main函数的第二个参数char *argv[]
可以看到rsi保存的第二个参数argv的地址存在-32(%rbp)处
第一个参数argc的地址在-20(%rbp),第二个参数argv的地址存在-32(%rbp)处
这里显示了调用printf函数的过程,参数分别存在寄存器rdi和rsi中
使用ret指令可以实现返回到上一个函数。需要注意如果使用了被调用者保存的寄存器,要从栈中把原始值取出返还给这些寄存器后再返回
3.4 本章小结
本章主要讲述了编译器的作用以及如何处理各种数据和操作,还有c语言各种操作对应的汇编代码。
第4章 汇编
4.1 汇编的概念与作用
汇编器(as)将汇编程序翻译成机器语言指令,把这些指令打包成可重定位目标程序的格式,并将结果保存在.o 目标文件中,.o 文件是一个二进制文件,它包含程序的指令编码。
4.2 在Ubuntu下汇编的命令
4.3 可重定位目标elf格式
作用:包含elf文件的魔数、头表的大小、起始地址、机器类型、section的数量和大小、节区头部表的一些信息等
作用:节区头部表,包含了个节的一些信息,如:起始地址、大小等
作用:重定位节(.rela.text): .text 节中位置的列表,包含.text节中需要进行重定位的信息,当链接器把目标文件和其他文件组合时,需要修改这些位置。
信息:包括符号和类型两个部分,符号在前面四个字节,类型在后面四个字节
加数:一个有符号常数,一些重定位要使用它对被修改引用的值做偏移调整
4.4 Hello.o的结果解析
1.分支转移:hello.s文件中分支转移是使用段名称进行跳转,而hello.o文件中分支转移是通过地址进行跳转的
4.5 本章小结
第5章 链接
5.1 链接的概念与作用
链接是将各种代码和数据片段收集并组合为单一文件的过程,这个文件可以被加载(复制)到内存并执行。
5.2 在Ubuntu下链接的命令
5.3 可执行目标文件hello的格式
作用:包含elf文件的魔数、头表的大小、起始地址、机器类型、section的数量和大小、节区头部表的一些信息等
作用:节区头部表,包含了个节的一些信息,如:起始地址、大小等
5.4 hello的虚拟地址空间
查看edb得出,hello虚拟地址起始于0x400000, 结束于0x405000。
- 链接的重定位过程分析
Hello:
图24
Hello.o:
图25
经过对hello和hello.o的比较分析,可以看出hello反汇编的代码有明确的虚拟地址,即完成了重定位,而hello.o中虚拟地址为0,未完成重定位。
同时,对于全局变量使用的R_X86_64_PLT32类型的重定位,链接后把lea变为了mov,即直接把计算出的地址赋值,而R_X86_64_PC32的重定位类型则是把0填上了绝对地址
5.6 hello的执行流程
ld-2.27.so!_dl_start—
ld-2.27.so!_dl_init—
hello!_start—
hello!_init—
hello!main—
hello!puts@plt–
hello!exit@plt–
hello!printf@plt–
hello!sleep@plt–
hello!getchar@plt–
sleep@plt—
5.7 Hello的动态链接分析
在进行动态链接前,首先进行静态链接,生成部分链接的可执行目标文件hello。此时共享库中的代码和数据没有被合并到hello中。加载hello时,动态链接器对共享目标文件中的相应模块内的代码和数据进行重定位,加载共享库,生成完全链接的可执行目标文件。
动态链接采用了延迟加载的策略,即在调用函数时才进行符号的映射。使用偏移量表GOT+过程链接表PLT实现函数的动态链接。GOT中存放函数目标地址,为每个全局函数创建一个副本函数,并将对函数的调用转换成对副本函数调用。
调用init之前的.got.plt
调用init之后的.got.plt
图26
5.8 本章小结
概括了链接的概念和作用,重点分析了hello程序的虚拟地址空间、重定位和执行过程。简述了动态链接的原理
第6章 hello进程管理
6.1 进程的概念与作用
进程是执行中程序的实例,有其自己的地址空间,进程为客户提供了一种假象:
(1)我们的进程是系统中当前唯一运行的程序,独占处理器和内存。
(2)处理器无间断地执行进程。
6.2 简述壳Shell-bash的作用与处理流程
Linux系统中shell是交互型应用级程序,代表用户运行其他程序。
其基本功能是解释并运行用户的指令,重复如下处理过程:
(1)终端进程读取用户通过键盘输入的命令行。
(2)分析命令行字符串,获取命令行参数,并构造传递给execve的argv向量
(3)检查第一个命令行参数是否是一个内置的shell命令
(4)如果不是内部命令,调用fork( )创建子进程
(5)在子进程中,用步骤2获取的参数,调用execve( )执行指定程序。
(6)如果用户没要求后台运行(命令末尾没有&号)则shell使用waitpid(或wait…)等待作业终止后返回。
(7)如果用户要求后台运行(如果命令末尾有&号),则shell返回;
6.3 Hello的fork进程创建过程
终端程序通过调用fork()函数创建一个子进程,子进程得到与父进程完全相同但是独立的一个副本,包括代码段、段、数据段、共享库以及用户栈。子进程还获得与父进程任何打开文件描述符相同的副本,父进程和子进程最大的不同时他们的PID是不同的。父进程与子进程是并发运行的独立进程,内核能够以任意方式交替执行它们的 逻辑控制流的指令。在子进程执行期间,父进程默认选项是显示等待子进程的完成。
6.4 Hello的execve过程
在创建了一个子进程后,子程序调用execve函数在上下文加载hello程序。
(1)删除当前虚拟地址中已存在的用户区域。
(2)为新程序建立新的区域结构,这些区域结构是私有的,虚拟地址空间的代码和数据区域被映射为hello文件的.txt和.data区,bss区域是请求二进制零的,映射匿名文件,其大小包含在hello文件中。栈和堆区域也是请求二进制零的,初始长度为零。
(3)如果hello与共享对象链接,那么这些对象都被动态链接到这个程序,然后映射到用户虚拟地址空间中的共享区域。
(4)设置程序计数器,使之指向代码区域的入口点,下次调用这个进程时,从这个入口点开始执行。
6.5 Hello的进程执行
逻辑控制流:如果想用调试器单步执行程序,我们会看到一系列的程序计数器(PC)的值,这些值唯一地对应于包含在程序的可执行目标文件中的指令,或是包含在运行时动态链接到程序的共享对象中的指令。这个PC值的序列叫做逻辑控制流,或者简称为逻辑流。
上下文切换:如果系统调用因为等待某个事件发生而阻塞,那么内核可以让当前进程休眠,切换到另一个进程,上下文就是内核重新启动一个被抢占的进程所需要的状态,是一种比较高层次的异常控制流。。
时间片:一个进程执行它的控制流的一部分的每一时间段叫做时间片。
用户模式和内核模式:shell使得用户可以有机会修改内核,所以需要设置一些防护措施来保护内核,如限制指令的类型和可以作用的范围。
开始Hello运行在用户模式,收到信号后进入内核模式,运行信号处理程序,之后再返回用户模式。运行过程中,cpu不断切换上下文,使运行过程被切分成时间片,与其他进程交替占用cpu,实现进程的调度。
6.6 hello的异常与信号处理
执行过程可能出现的异常一共有四种:中断、陷阱、故障、终止。
中断:来自I/O设备的信号,异步发生,总是返回到下一条指令。
陷阱:有意的异常,同步发生,总是返回到下一条指令。
故障:潜在可恢复的错误,同步发生,可能返回到当前指令或终止。
终止:不可恢复的错误,同步发生,不会返回。
- 正常执行
图27
- 输入ctrl+z将进程挂起并转到后台运行
图28
输入ps查看,可以看到hello仍在执行
图29
- 输入crtl+c将所有前台进程终止
图30
- 乱输入
程序运行时乱按键盘,会发现屏幕的输入缓存到stdin。getchar的时候读出一个’\n’结尾的字符串,其他当作命令行输入
图31
6.7本章小结
本章阐述了进程的概念与作用,Shell的一般处理流程,分析了hello进程的执行过程,创建、加载和终止,以及hello的异常与信号处理。
第7章 hello的存储管理
7.1 hello的存储器地址空间
1.逻辑地址:程序编译后出现在汇编代码中的地址,用来指定一个操作数或一条指令的地址,由段标识符加上偏移量表示。
2.线性地址:一个逻辑地址经过段地址机制转化后变成一个线性分页地址,线性地址可以再经过物理地址变换以产生一个新的物理分页地址。线性地址是逻辑地址和物理地址变换的中间层。
3.虚拟地址:即线性地址
4.物理地址:用于内存芯片级的单元寻址,与处理器和CPU链接的地址总线相对应。可以直接把物理地址理解成插在机器上的内存本身,把内存看成一个从0字节一直到最大空量逐字节编号的大数组,把这个数组叫做物理地址
7.2 Intel逻辑地址到线性地址的变换-段式管理
首先,给定一个完整的逻辑地址[段选择符:段内偏移地址],
1.看段选择符的T1=0还是1,判断当前要转换是GDT中的段还是LDT中的段,再根据相应寄存器,得到其地址和大小。我们就有了一个数组。
2.拿出段选择符中前13位,可以在这个数组中,查找到对应的段描述符,这样基地址就知道了。
3.把Base + offset,就是要转换的线性地址了。
7.3 Hello的线性地址到物理地址的变换-页式管理
页式管理是一种内存空间存储管理的技术,页式管理分为静态页式管理和动态页式管理。将各进程的虚拟空间划分成若干个长度相等的页(page),页式管理把内存空间按页的大小划分成片或者页面(page frame),然后把页式虚拟地址与内存地址建立一一对应页表,并用相应的硬件地址变换机构,来解决离散地址变换问题。页式管理采用请求调页或预调页技术实现了内外存存储器的统一管理。
图32
7.4 TLB与四级页表支持下的VA到PA的变换
每次cpu发现需要重新翻译一个虚拟地址时,它就必须发送一个vpn得到虚拟地址mmu,发送一个vpo位得到一个l1高速缓存.例如当我们使用mmu向一个tlb的组请求一个页表中的条目时,l1高速缓存通过一个vpo位在页表中查找一个相应的数据标记组,并在页表中读出这个组里的个数据标记和相应的数据关键字.当mmu从一个tlb的组得到一个ppn时,代表缓存的工作在这个组的请求之前已经完全准备好,这个组的ppn与就已经可以与这些数据标记文件中的一个虚拟地址进行很好的匹配了。
corei7采用四级页表层次结构,每个四级页表进程都有他自己私有的页表层次结构,这种设计方法从两个基本方面就是减少了对内存的需求,如果一级页表的pte全部为空,那么二级页表就不会继续存在,从而为进程节省了大量的内存,而且也只有一级页表才会有需要总是在一个内存中。正在上传…
图33
7.5 三级Cache支持下的物理内存访问
首先,组选择取出虚拟地址的组索引位,将二进制组索引转化为一个无符号整数,找到相应的组然后行匹配把虚拟地址的标记为拿去和相应的组中所有行的标记位进行比较,当虚拟地址的标记位和高速缓存行的标记位匹配时,而且高速缓存行的有效位是1,则高速缓存命中。字选择一旦高速缓存命中,我们就知道我们要找的字节在这个块的某个地方。因此块偏移位提供了第一个字节的偏移。把这个字节的内容取出返回给CPU。对于不命中的情况,如果高速缓存不命中,那么需要从存储层次结构中的下一层取出被请求的块,然后将新的块存储在组索引位所指示的组中的一个高速缓存行中。一种简单的 放置策略如下:如果映射到的组内有空闲块,则直接放置,否则组内都是有效块,产生冲突(evict),则采用最近最少使用策略 LFU 进行替换。
7.6 hello进程fork时的内存映射
当fork函数被当前进程调用时,内核为新进程创建各种数据结构,并分配给它一个唯一的PID,同时为这个新进程创建虚拟内存。它创建了当前进程的mm_struct、区域结构和页表的原样副本。它将两个进程中的每个页面都标记位只读,并将两个进程中的每个区域结构都标记为私有的写时复制。当fork在新进程中返回时,新进程现在的虚拟内存刚好和调用fork时存在的虚拟内存相同。当这两个进程中的任一个后来进行写操作时,写时复制机制就会创建新页面。因此,也就为每个进程保持了私有空间地址的抽象概念。
7.7 hello进程execve时的内存映射
execve函数在当前代码共享进程的上下文中加载并自动运行一个新的代码共享程序,它可能会自动覆盖当前进程的所有虚拟地址和空间,删除当前进程虚拟地址的所有用户虚拟和部分空间中的已存在的代码共享区域和结构,但是它并没有自动创建一个新的代码共享进程。新的运行程序仍然在堆栈中拥有相同的区域pid。之后为新运行程序的用户共享代码、数据、bss和所有堆栈的区域结构创建新的共享区域和结构,这一步叫通过链接映射到新的私有代码共享区域,所有这些新的代码共享区域都可能是在运行时私有的、写时复制的。它首先映射到一个共享的区域,hello这个程序与当前共享的对象libc.so链接,它可能是首先动态通过链接映射到这个代码共享程序上下文中的,然后再通过映射链接到用户虚拟地址和部分空间区域中的另一个共享代码区域内。为了设置一个新的程序计数器,execve函数要做的最后一件要做的事情就是自动设置当前代码共享进程上下文的一个程序计数器,使之成为指向所有代码共享区域的一个入口点(即_start函数)
7.8 缺页故障与缺页中断处理
在发生缺页中断之后,具体的操作过程如下:
第1步:CPU生成一个虚拟地址,并把它传送给MMU.
第2步: 地址管理单元生成PTE地址,并从高速缓存/主存请求得到它.
第3步:高速缓存/主存向MMU返回PTE.
第4步:PTE中的有效位是零,所以MMU触发了一次异常,传递CPU中的控制到操作系统内核中的缺页异常处理程序.
第5步:缺页处理程序确定出物理内存中的牺牲页,如果这个页面已经被修改了,则把它换出到磁盘.
第6步:缺页处理程序页面调人新的页面,并更新内存中的PTE.
第7步: 缺页处理程序返回地址到原来的缺页处理进程,再次对主存执行一些可能导致缺页的处理指令,cpu,然后将返回地址重新再次发送给处理程序mmu.因为程序中虚拟的页面现在已经完全缓存在了物理的虚拟内存中,所以处理程序会再次命中,主存将所请求字符串的返回地址发送给虚拟内存的处理器。
7.9动态存储分配管理
动态内存分配器维护着一个进程的虚拟内存区域,称为堆。分配器将堆视为一组不同的大小的块的集合来维护。每个块就是一个连续的虚拟内存片,要么是已分配的,要么是空闲的。分配器有两种基本风格。两种风格都是要求显示的释放分配块。
1.显式分配器:要求应用显示的释放任何已分配的块。例如C标准库提供一个叫做malloc程序包的显示分配器。
2.隐式分配器:要求分配器检测一个已分配块何时不再被程序使用,那么就释放这个块。隐式分配器也叫垃圾收集器。
7.10本章小结
本章主要介绍了hello存储器的地址空间;虚拟地址到物理地址的转换;cache的物理内存访问;进程 fork、execve 时的内存映射、缺页故障与缺页中断处理;动态存储分配管理。
(第7章 2分)
第8章 hello的IO管理
8.1 Linux的IO设备管理方法
一个Linux文件就是一个m个字节的序列,:所有的 IO 设备都被模型化为文件,而所有的输入和输出都被 当做对相应文件的读和写来执行,这种将设备优雅地映射为文件的方式,允许 Linux 内核引出一个简单低级的应用接口,称为 Unix I/O。
8.2 简述Unix IO接口及其函数
Unix I/O 函数:
int open(char* filename,int flags,mode_t mode) 。open 函数将 filename(文件名,含后缀)转换为一个文件描述符(C 中表现为指针),并且 返回描述符数字。
int close(fd),fd 是需要关闭的文件的描述符(C 中表现为指针),close 返回操作结果。
ssize_t read(int fd, void *buf, size_t n);read 函数从描述符为fd 的当前文件位置复制最多n 个字节到内存位置buf .返回值-1表示一个错误,而返回值0 表示EOF.否则,返回值表示的是实际传送的字节数量.
ssize_t write(int fd, const void *buf, size_t n);
write 函数从内存位置buf 复制至多n 个字节到描述符fd 的当前文件位置.图10-3 展示了一个程序使用read 和write 调用一次一个字节地从标准输入复制到标准输出.返回:若成功则为写的字节数,若出错则为-1.
8.3 printf的实现分析
printf程序按照格式fmt结合参数args生成格式化之后的字符串,并返回字串的长度。
int printf(const char *fmt, ...)
{
int i;
char buf[256];
va_list arg = (va_list)((char*)(&fmt) + 4);
i = vsprintf(buf, fmt, arg);
return i;
}
vsprintf函数(在printf函数内部调用),vsprintf的作用就是格式化。它接受确定输出格式的格式字符串fmt。用格式字符串对个数变化的参数进行格式化,产生格式化输出。
int vsprintf(char *buf, const char *fmt, va_list args)
{
char* p;
char tmp[256];
va_list p_next_arg = args;
for (p=buf;*fmt;fmt++) {
if (*fmt != '%') {
*p++ = *fmt;
continue;
}
fmt++;
switch (*fmt) {
case 'x':
itoa(tmp, *((int*)p_next_arg));
strcpy(p, tmp);
p_next_arg += 4;
p += strlen(tmp);
break;
case 's':
break;
default:
break;
}
}
return
在printf中调用系统函数write(buf,i)将长度为i的buf输出,在write函数中,将栈中参数放入寄存器,ecx是字符个数,ebx存放第一个字符地址,
int INT_VECTOR_SYS_CALLA代表通过系统调用syscall
write:
mov eax, _NR_write
mov ebx, [esp + 4]
mov ecx, [esp + 8]
int INT_VECTOR_SYS_CALL
syscall将字符串中的字节从寄存器中通过总线复制到显卡的显存中,显存中存储的是字符的ASCII码。
字符显示驱动子程序将通过ASCII码在字模库中找到点阵信息将点阵信息存储到vram中。
显示芯片会按照一定的刷新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点(RGB分量)。于是我们的打印字符串就显示在了屏幕上。从vsprintf生成显示信息,到write系统函数,到陷阱-系统调用 int 0x80或syscall.
字符显示驱动子程序:从ASCII到字模库到显示vram(存储每一个点的RGB颜色信息)。显示芯片按照刷新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点(RGB分量)
sys_call:
call save
push dword [p_proc_ready]
sti
push ecx
push ebx
call [sys_call_table + eax * 4]
add esp, 4 * 3
mov [esi + EAXREG - P_STACKBASE], eax
cli
ret
8.4 getchar的实现分析
异步异常-键盘中断的处理:在用户敲击或者按键盘上面的按钮的时候,键盘接口获得一个键盘扫描码,这样会在此时同时产生一个中断的请求,这会调用键盘中断处理子程序。接受按键扫描码转成ascii码,保存到系统的键盘缓冲区的内部。getchar等调用read系统函数,通过系统调用读取按键ascii码,直到接受到回车键才返回这个字符串。Getchar的大概思想是读取字符串的第一个字符之后再进行返回操作。
int getchar(void)
{
static char buf[BUFSIZ];
static char *bb = buf;
static int n = 0;
if(n == 0)
{
n = read(0, buf, BUFSIZ);
bb = buf;
}
return(--n >= 0)?(unsigned char) *bb++ : EOF;
}
8.5本章小结
本章介绍了 Linux 的 I/O 设备的基本概念和管理方法,Unix I/O 接口及其函数,printf 函数和 getchar 函数的工作过程。
(第8章1分)
结论
Hello的一生,首先是程序员通过各种ide把它写成.c文件,然后用预处理文件将各种宏定义展开,接着就是编译器将.i文件编译为汇编文件.s,这其中经过了许多的优化、重写等,然后在由汇编器将其转换为可重定位的二进制目标文件,这时的hello.i已经变为机器码,也就是计算机已经能识别一些内容了,但是还需要链接器通过链接将其进行重定位、符号解析等操作,以便其能成功的实现功能并映射到内存之中进行操作。最终,在虚拟内存的机制下,程序真正的运行了起来。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分)
哈工大2022计算机系统大作业相关推荐
- 【哈工大2022计算机系统大作业“程序人生”】
计算机系统 大作业 题 目 程序人生-Hello's P2P 专 业 计算机 学 号 120L021504 班 级 2003012 学 生 乔江洋 指 导 教 师 郑贵滨 计算机科学与技术学院 202 ...
- 哈工大2022计算机系统大作业---程序人生
计算机系统 大作业 题 目 程序人生-Hello's P2P 专 业 计算机类 学 号 120L021923 班 级 2003006 学 生 甄自镜 指 导 ...
- 2022计算机系统大作业——程序人生-Hello’s P2P
计算机系统 大作业 题 目 程序人生-Hello's P2P 专 业 计算机 学 号 120L021716 班 级 2003005 学 生 蔡泽栋 指 导 ...
- 哈尔滨工业大学2022计算机系统大作业
计算机系统 大作业 题 目 程序人生-Hello's P2P 专 业 计算机 学 号 120L021411 班 级 2003011 学 生 张洪博 指 导 ...
- 2022计算机系统大作业————hit
-/************************************************************************************************** ...
- 哈工大csapp计算机系统大作业
计算机系统 大作业 题 目 程序人生-Hello's P2P 专 业 计算学部 学 号 120L022009 班 级 2003007 学 生 李沛聪 指 导 教 ...
- 哈工大2022年大作业——程序人生
- 哈工大计算机系统大作业 程序人生-Hello’s P2P 2022
2022哈工大计算机系统大作业 目录 摘 要 第1章 概述 1.1 Hello简介 1.2 环境与工具 1.3 中间结果 1.4 本章小结 第2章 预处理 2.1 预处理的概念与作用 2.2在Ubun ...
- 【2022】哈工大计算机系统大作业——程序人生Hello’s P2P
2022哈工大计算机系统大作业--程序人生Hello's P2P 摘要 第1章 概述 1.1 Hello简介 1.2 环境与工具 1.3 中间结果 1.4 本章小结 第2章 预处理 2.1 预处理的概 ...
最新文章
- 如何导出项目到本地_【点滴故事】:如何做项目本地化?
- asp.net 开发注意的几点
- LINUX装魂斗罗游戏,魂斗罗战甲1-支援形态装置搭配思路及攻略
- platform平台总线
- python get sheet_Python模块学习 - openpyxl
- mysql sql长度限制_SQL限制– MySQL限制
- python列表后面两个括号_python列表[]中括号
- 生成可编辑的pdf(可java代码动态赋值)
- python批量修改图片格式、重命名
- Arcgis学习视频
- php镜像站群_【镜像站群系统】2020最新单域名PHP网站克隆镜像网站程序源码
- 联想入选恒生指数成分股
- 4针串口线接法图_串口硬盘4针的小接口怎么样连接
- 3分钟教你如何在Word里快速制作单斜线和多斜线表头
- 平面设计需要学习什么,平面设计是什么;夏雨老师
- 解决Windows下cmder中使用babun运行conda命令报错TypeError: LoadLibrary() argument 1 must be str, not None
- java一元多项式减法运算_一元多项式的表示及加减乘除运算
- 【宇通23届招聘内推】
- [RabbitMQ--1] MQ简介
- 基于requests和lxml库爬取优信二手车
热门文章
- 敏捷项目如何保证测试质量
- 如何使用	Pixelmator Pro调整照片,打印出最完美的照片效果?
- Unittest-单元测试3
- 考研二战日记-第16天小结
- 序列、列表、列表的方法以及遍历序列
- python判定素数_素数判定python
- python金融大数据分析师工资待遇_请问数据分析师这个工作怎么样,是否值得成为努力方向?...
- 如何在 Windows 10 中安装 WSL2 的 Linux 子系统
- android推送设备id,第三方推送ID配置
- 遇见逆水寒服务器维护时间,《遇见逆水寒》7月23日更新公告