版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、综合实验报告( 2013 - 2014 年度第 1 学期)名 称: 操作系统综合实验 题 目: 基于OS Lab的操作系统综合实验 院 系: 计算机系 班 级: 网络 学 号: 201 学生姓名: 指导教师: 王平,王晓辉 设计周数: 1 成 绩: 日 期: 2013 年 12 月 实验一:实验环境的使用1、 实验目的:1、熟悉操作系统集成实验环境OS Lab的基本使用方法。 2、练习编译、调试EOS操作系统内核以及EOS应用程序。 二、实验内容:1、启动OS Lab2、学习OS Lab的基本使用方法 3、EOS内核项目的生成和调试 4、EOS应用程序项目的生成和调试 5、退出OS Lab 6
2、、保存EOS内核项目 三、实验过程:本实验实验过程主要按照eos操作系统实验教程上所对应的章节来进行。实验结果:(一)启动OS Lab :(无)(二)学习OS Lab的基本使用方法 :(1)、创建了第一个项目:(2)、生成了第一个项目(3) 、添加了func文件后经过一系列的调试,打印出了相关内容,按shift+F5结束调试。(4)、查看变量的值:有3种方法:1、将鼠标移动到源代码编辑器中变量n的名称上,此时会弹出一个窗口显示出变量n当前的值(由于此时还没有给变量n赋值,所以是一个随机值)。 2、在源代码编辑器中变量n的名称上点击鼠标右键,在弹出的快捷菜单中选择“快速监视”,可以使用“快速监视
3、”对话框查看变量n的值。然后,可以点击“关闭”按钮关闭“快速监视”对话框。 3、在源代码编辑器中变量n的名称上点击鼠标右键,在弹出的快捷菜单中选择“添加监视”,变量n就被添加到了“监视”窗口中。使用“监视”窗口可以随时查看变量的值和类型。此时按F10进行一次单步调试,可以看到“监视”窗口中变量n的值会变为0(1)、调用堆栈 :使用“调用堆栈”窗口可以在调试的过程中查看当前堆栈上的函数,还可以帮助理解函数的调用层次和调用过程。EOS内核项目的生成和调试 :(2)、新建EOS内核项目 (3)、生成项目 (4)、调试项目 (5)、查看软盘镜像文件中的内容 (6)、查看EOS SDK(Software
4、 Development Kit)文件夹 EOS应用程序项目的生成和调试 新建EOS应用程序项目 生成项目 :按F7生成项目调试项目 :按F5进行各种调试查看软盘镜像文件中的内容 :使用FloppyImageEditor工具打开该项目中的Floppy.img文件,查看软盘镜像中的文件。L修改EOS应用程序项目名称 (三)退出(四)保存四、实验总结:经过试验1,我理解了OS Lab的基本操作方法和主要用途,这为以后的试验打下了基础。实验二: 操作系统的启动一、 实验目的l跟踪调试 EOS 在 PC 机上从加电复位到成功启动的全过程,了解操作统的启动过程。查看 EOS 启动后的状态和行为,理解操作
5、系统启动后的工作方式。二、 实验内容及其实验步骤3.1 准备实验1. 启动 OS Lab。2. 新建一个 EOS Kernel 项目。3. 在“项目管理器”窗口中打开 boot 文件夹中的 boot.asm 和 loader.asm 两个汇编文件。boot.asm是软盘引导扇区程序的源文件,loader.asm 是 loader 程序的源文件。简单阅读一下这两个文件中的 NASM 汇编代码和注释。4. 按 F7 生成项目。5. 生成完成后,使用 Windows 资源管理器打开项目文件夹中的 Debug 文件夹。找到由 boot.asm 生成的软盘引导扇区程序 boot.bin 文件,该文件的大
6、小一定为 512 字节(与软盘引导扇区的大小一致)。找到由 loader.asm 生成的 loader 程序 loader.bin 文件,记录下此文件的大小 1566 字节,在下面的实验中会用到。找到由其它源文件生成的操作系统内核文件 kernel.dll。3.2 调试 EOS 操作系统的启动过程3.2.1 使用 Bochs 做为远程目标机3.2.2 调试 BIOS 程序启动调试后,Bochs 在 CPU 要执行的第一条指令(即 BIOS 的第一条指令)处中断。 此时,Display窗口没有显示任何内容,Console 窗口显示要执行的 BIOS 第一条指令的相关信息,并等待用户输入调试命令,
7、如图 10-1:从 Console 窗口显示的内容中,我们可以获得关于 BIOS 第一条指令的如下信息:行首的0xfffffff0表示此条指令所在的物理地址。lf000:fff0 表示此条指令所在的逻辑地址(段地址:偏移地址)。ljmp far f000:e05b 是此条指令的反汇编代码。l行尾的 ea5be000f0 是此条指令的十六进制字节码,可以看出此条指令有 5 个字节。接下来可以按照下面的步骤,查看 CPU 在没有执行任何指令之前主要寄存器中的数据,以及内存中的数据:1. 在 Console 窗口中输入调试命令 sreg 后按回车,显示当前 CPU 中各个段寄存器的值,如图 10-2
8、。其中 CS 寄存器信息行中的“s=0xf000”表示 CS 寄存器的值为 0xf000。2. 输入调试命令 r 后按回车,显示当前 CPU 中各个通用寄存器的值,如图 10-3。其中“rip:0x00000000:0000fff0”表示 IP 寄存器的值为 0xfff0。3. 输入调试命令 xp /1024b 0x0000,查看开始的 1024 个字节的物理内存。在 Console 中输出的这1K 物理内存的值都为 0,说明 BIOS 中断向量表还没有被加载到此处。4. 输入调试命令 xp /512b 0x7c00,查看软盘引导扇区应该被加载到的内存位置。输出的内存值都为 0,说明软盘引导扇
9、区还没有被加载到此处。3.2.3 调试软盘引导扇区程序3.2.4 调试加载程序3.2.5 调试内核调试内核的步骤如下:1. 在 OS Lab 的“项目管理器”窗口中打开 ke 文件夹中的 start.c 文件,此文件中只定义了一个函数,就是操作系统内核的入口点函数 KiSystemStartup。2. 在 KiSystemStartup 函数中的代码行(第 61 行)KiInitializePic();添加一个断点。3. 现在可以在 Console 窗口中输入调试命令 c 继续调试,在刚刚添加的断点处中断。4. 在 start.c 源代码文件中的 KiSystemStartup 函数名上点击鼠
10、标右键,在弹出的快捷菜单中选择“添加监视”,KiSystemStartup 函数就被添加到了“监视”窗口中。在“监视”窗口中可以看到此函数地址为void (PVOID) 0x800* <KiSystemStartup>与在虚拟内存 x80001117 处保存的函数入口地址相同,说明的确是由 Loader 程序进入了操作系统内核。5. 按 F5 继续执行 EOS 操作系统内核,在 Display 窗口中显示 EOS 操作系统已经启动,并且控制台EOS 操作系统实验教程北京海西慧学科技有限公司 126程序已经开始运行了。3.2.6 EOS 启动后的状态和行为查看 EOS 的版本号:1.
11、 在控制台中输入命令“ver”后按回车。2. 输出 EOS 版本后的控制台如图 10-4 所示。查看 EOS 启动后的进程和线程的信息:1. 在控制台中输入命令“pt”后按回车。2. 输出的进程和线程信息如图 10-5 所示。3.2.6 EOS 启动后的状态和行为三. 实验总结 通过本实验了解操作系统的启动过程,理解操作系统启动后的工作方式。实验三:进程的创建:一、实验目的:1、练习使用EOS API函数CreateProcess创建一个进程,掌握创建进程的方法,理解进程和程序的区别。 2、调试跟踪CreateProcess函数的执行过程,了解进程的创建过程,理解进程是资源分配的单位。 二、
12、实验内容:1、准备实验:新建一个EOS Kernel项目,分别使用Debug配置和Release配置生成此项目。新建一个EOS应用程序项目,使用在第EOS Kernel生成的SDK文件夹覆盖EOS应用程序项目文件夹中的SDK文件夹。 2、练习使用控制台命令创建EOS应用程序的进程 3、练习通过编程的方式让应用程序创建另一个应用程序的进程 4、调试CreateProcess函数 5、调试PsCreateProcess函数 6、练习通过编程的方式创建应用程序的多个进程 三、实验过程:1、准备实验:(无)2、练习使用控制台命令创建EOS应用程序的进程:使用FloppyImageEditor工具将本实
13、验文件夹内的Hello.exe文件添加到Floppy.img文件中。启动调试,在EOS的控制台中输入命令“A:Hello.exe”后回车。 得到结果:3、练习通过编程的方式让应用程序创建另一个应用程序的进程 :使用NewProc.c文件中的源代码替换之前创建的EOS应用程序项目中的EOSApp.c文件内的源代码。 启动调试,得到如下结果:可以看到父进程(EOSApp.exe)首先开始执行并输出内容,父进程创建了子进程(Hello.exe)后,子进程开始执行并输出内容,待子进程结束后父进程再继续执行。 4、调试CreateProcess函数:按F5启动调试EOS应用程序,在弹出异常对话框后点“是
14、”,在main函数中调用CreateProcess函数的代码行添加一个断点。5、调试PsCreateProcess函数:在PsCreateProcess函数中找到调用PspCreateProcessEnvironment函数的代码行添加一个断点。 进入此中断,按F11进入PspCreateProcessEnvironment函数。 在调用ObCreateObject函数的代码行添加一个断点,进入此中断,将表达式*NewProcess添加到“监视”窗口中,监视其值得变化。接下来调试初始化进程控制块中各个成员变量的过程: 1) 首先创建进程的地址空间,即4G虚拟地址空间。2)按F5继续调试,到此断
15、点处中断。 3)按F10执行此行代码后中断。 4)在“监视”窗口中查看进程控制块的成员变量Pas的值已经不再是0。说明已经初始化了进程的4G虚拟地址空间。 5)使用F10一步步调试PspCreateProcessEnvironment函数中后面的代码,在调试的过程中根据执行的源代码,查看“监视”窗口中*NewProcess表达式的值,。 6)当从PspCreateProcessEnvironment函数返回到PsCreateProcess函数后,停止按F10。此时“监视”窗口中已经不能再显示表达式*NewProcess的值了,在PsCreateProcess函数中是使用ProcessObjec
16、t指针指向进程控制块的,所以将表达式*ProcessObject添加到“监视”窗口中就可以继续观察新建进程控制块中的信息。 7)接下来继续使用F10一步步调试PsCreateProcess函数中的代码,同样要注意观察执行后的代码修改了进程控制块中的哪些成员变量。8)按F5继续执行,EOS内核会为刚刚初始化完毕的进程控制块新建一个进程。激活虚拟机窗口查看新建进程执行的结果。 9)在OS Lab中选择“调试”菜单中的“停止调试”结束此次调试。 10)选择“调试”菜单中的“删除所有断点”。 结果:代码:/*提供该示例代码是为了阐释一个概念,或者进行一个测试,并不代表着最安全的编码实践,因此不应在应用
17、程序或网站中使用该示例代码。对于超出本示例代码的预期用途以外的使用所造成的偶然或继发性损失,北京海西慧学科技有限公司不承担任何责任。*/#include "EOSApp.h"/ main 函数参数的意义:/ argc - argv 数组的长度,大小至少为 1,argc - 1 为命令行参数的数量。/ argv - 字符串指针数组,数组长度为命令行参数个数 + 1。其中 argv0 固定指向当前/ 进程所执行的可执行文件的路径字符串,argv1 及其后面的指针指向各个命令行/ 参数。/ 例如通过命令行内容 "a:hello.exe -a -b" 启动进程后
18、,hello.exe 的 main 函/ 数的参数 argc 的值为 3,argv0 指向字符串 "a:hello.exe",argv1 指向/ 参数字符串 "-a",argv2 指向参数字符串 "-b"。/int main(int argc, char* argv)/ 启动调试 EOS 应用程序前要特别注意下面的问题:/ 1、如果要在调试应用程序时能够调试进入内核并显示对应的源码,/ 必须使用 EOS 核心项目编译生成完全版本的 SDK 文件夹,然/ 后使用此文件夹覆盖应用程序项目中的 SDK 文件夹,并且 EOS/ 核心项目在磁盘
19、上的位置不能改变。/ 2、在启动调试应用程序之前必须首先删除/禁用所有的断点,在断/ 点中断 (int 3) 被命中后才能重新添加/启用断点,否则启动/ 调试会失败。/STARTUPINFO StartupInfo;PROCESS_INFORMATION ProcInfoOne5;ULONG ulExitCode;/ 子进程退出码INT nResult = 0;/ main 函数返回值。0 表示成功,非 0 表示失败。#ifdef _DEBUG_asm("int $3n nop");#endifprintf("Create two processes and wa
20、it for the processes exit.nn");/ 使子进程和父进程使用相同的标准句柄。/StartupInfo.StdInput = GetStdHandle(STD_INPUT_HANDLE);StartupInfo.StdOutput = GetStdHandle(STD_OUTPUT_HANDLE);StartupInfo.StdError = GetStdHandle(STD_ERROR_HANDLE);/ 为一个应用程序同时创建两个子进程。/int i=0;for(;i<5;i+)if (CreateProcess("A:Hello.exe&
21、quot;, NULL, 0, &StartupInfo, &ProcInfoOnei) / 创建子进程成功,等待子进程运行结束。/WaitForSingleObject(ProcInfoOnei.ProcessHandle, INFINITE);/WaitForSingleObject(ProcInfoTwo.ProcessHandle, INFINITE);/ 得到并输出子进程的退出码。/GetExitCodeProcess(ProcInfoOnei.ProcessHandle, &ulExitCode);printf("nThe process one
22、exit with %d.n", ulExitCode);/GetExitCodeProcess(ProcInfoTwo.ProcessHandle, &ulExitCode);/printf("nThe process two exit with %d.n", ulExitCode);/ 关闭不再使用的句柄。/CloseHandle(ProcInfoOnei.ProcessHandle);CloseHandle(ProcInfoOnei.ThreadHandle);/CloseHandle(ProcInfoTwo.ProcessHandle);/Clos
23、eHandle(ProcInfoTwo.ThreadHandle); else printf("CreateProcess Failed, Error code: 0x%X.n", GetLastError();nResult = 1;return nResult;实验四:线程的状态和转换 一、实验目的:1、调试线程在各种状态间的转换过程,熟悉线程的状态和转换。 2、通过为线程增加挂起状态,加深对线程状态的理解。 二、实验内容及步骤:1、准备实验:新建一个EOS Kernel项目。 2、调试线程状态的转换过程:对第一步的项目启动调试,待EOS启动完毕,在EOS控制台中输入命
24、令“loop”后按回车。得到结果: 结束调试。1. 控制台派遣线程被唤醒,由阻塞状态进入就绪状态。 2. loop线程由运行状态进入就绪状态。 3. 控制台派遣线程由就绪状态进入运行状态。 4. 待控制台派遣线程处理完毕由于空格键被按下而产生的键盘事件后,派遣线程会由运行状态重新进入阻塞状态,开始等待下一个键盘事件到来。 5. loop线程由就绪状态进入运行状态,继续执行死循环。 按F5继续执行,在PspSelectNextThread函数中的断点处中断。按F5继续执行,在PspUnreadyThread函数中的断点处中断。在快速监视对话框中查看“*Thread”表达式的值。关闭快速监视对话框
25、后,在“调用堆栈”窗口中激活PspSelectNextThread函数对应的堆栈项,在“调用堆栈”窗口中激活PspUnreadyThread函数对应的堆栈项,然后按F10单步调试,直到返回PspSelectNextThread函数并将线程状态修改为Running。按F5继续执行,在PspWait函数中的断点处中断。3、为线程增加挂起状态:删除之前添加的所有断点。 按F5启动调试。 待EOS启动完毕,在EOS控制台中输入命令“loop”后按回车。此时可以看到loop线程的执行计数在不停增长,说明loop线程正在执行。记录下loop线程的ID。 按Ctrl+F2切换到控制台2,输入命令“suspe
26、nd 31”(如果loop线程的ID是31)后按回车。命令执行成功的结果如图12-2所示。 按Ctrl+1切换回控制台1,可以看到由于loop线程已经成功被挂起,其执行计数已经停止增长了。此时占用处理器的是EOS中的空闲线程。 Resume原语可以将一个被Suspend原语挂起的线程(处于静止就绪状态)恢复为就绪状态。但是PsResumThread函数中的这部分代码(第119行),完成这部分代码。代码:/*提供该示例代码是为了阐释一个概念,或者进行一个测试,并不代表着最安全的编码实践,因此不应在应用程序或网站中使用该示例代码。*/STATUSPsResumThread(IN HANDLE hT
27、hread)/*+功能描述:恢复指定的线程。参数:hThread - 需要被恢复的线程的句柄。返回值:如果成功则返回 STATUS_SUCCESS。-*/STATUS Status;BOOL IntState;PTHREAD Thread;/ 根据线程句柄获得线程对象的指针/Status = ObRefObjectByHandle(hThread, PspThreadType, (PVOID*)&Thread);if (EOS_SUCCESS(Status) IntState = KeEnableInterrupts(FALSE);/ 关中断if (Zero = Thread->
28、State) / 将线程从挂起线程队列中移除。/ListRemoveEntry(&Thread->StateListEntry);/ 将挂起的线程恢复为就绪状态。/ 线程由静止就绪状态(Static Ready)进入活动就绪状态(Active Ready)。/PspReadyThread(Thread);/ 执行线程调度,让刚刚恢复的线程有机会执行(如果真的能够调度到它的话)。/PspThreadSchedule();Status = STATUS_SUCCESS; else Status = STATUS_NOT_SUPPORTED;KeEnableInterrupts(Int
29、State);/ 开中断ObDerefObject(Thread);return Status;测试方法 :待读者完成Resume原语后,可以先使用suspend命令挂起loop线程,然后在控制台2中输入命令“Resume 31”(如果loop线程的ID是31)后按回车。 思考题:思考一下,在本实验中,当loop线程处于运行状态时, EOS 中还有哪些线程,它们分别处于什么状态。可以使用控制台命令pt查看线程的状态。3、 实验总结:明白了loop指令的用法以及resume原语的结构。实验五:进程的同步 一、实验目的:1、使用EOS的信号量,编程解决生产者消费者问题,理解进程同步的意义。 2、调
30、试跟踪EOS信号量的工作过程,理解进程同步的原理。 3、修改EOS的信号量算法,使之支持等待超时唤醒功能(有限等待),加深理解进程同步的原理。 二、实验内容和步骤:1、准备实验:新建一个EOS Kernel项目。 生成EOS Kernel项目,从而在该项目文件中生成SDK文件夹。新建一个EOS应用程序项目。使用在第3步生成的SDK文件夹覆盖EOS应用程序项目文件夹中的SDK文件夹。2、使用EOS的信号量解决生产者消费者问题:在本实验文件夹中,提供了使用EOS的信号量解决生产者消费者问题的参考源代码文件pc.c,仔细阅读此文件中的源代码和注释。使用pc.c文件中的源代码,替换之前创建的EOS应用
31、程序项目中EOSApp.c文件内的源代码。按F5启动调试。立即激活虚拟机窗口查看生产者消费者同步执行的过程。结果:3、调试EOS信号量的工作过程:启动调试,在main函数中创建Empty信号量的代码行添加一个断点。按F5继续调试,到此断点处中断。按F11调试进入CreateSemaphore函数。可以看到此API函数只是调用了EOS内核中的PsCreateSemaphoreObject函数来创建信号量对象。按F11调试进入semaphore.c文件中的PsCreateSemaphoreObject函数。在semaphore.c文件的顶部查找到PsInitializeSemaphore函数的定义
32、(第19行),在此函数的第一行(第39行)代码处添加一个断点。按F5继续调试,到断点处中断。观察PsInitializeSemaphore函数中用来初始化信号量结构体成员的值,应该和传入CreateSemaphore函数的参数值是一致的。按F10单步调试PsInitializeSemaphore函数执行的过程,查看信号量结构体被初始化的过程。打开“调用堆栈”窗口,查看函数的调用层次。 生产者和消费者刚开始执行时,用来放产品的缓冲区都是空的,所以生产者在第一次调用WaitForSingleObject函数等待Empty信号量时,应该不需要阻塞就可以立即返回。由于开始时生产者线程生产产品的速度较快
33、,而消费者线程消费产品的速度较慢,所以当缓冲池中所有的缓冲区都被产品占用时,生产者在生产新的产品时就会被阻塞。只有当消费者线程从缓冲池中消费了一个产品,从而产生一个空缓冲区后,生产者线程才会被唤醒并继续生产14号产品。4、修改EOS的信号量算法:现在要求同时修改PsWaitForSemaphore函数和PsReleaseSemaphore函数中的代码,使这两个参数能够真正起到作用,使信号量对象支持等待超时唤醒功能和批量释放功能。 测试方法:修改完毕后,可以按照下面的方法进行测试: 1. 使用修改完毕的EOS Kernel项目生成完全版本的SDK文件夹,并覆盖之前的生产者消费者应用程序项目的SD
34、K文件夹。 2. 按F5调试执行原有的生产者消费者应用程序项目,结果必须仍然与图13-2一致。如果有错误,可以调试内核代码来查找错误,然后在内核项目中修改,并重复步骤1。 3. 将Producer函数中等待Empty信号量的代码行 WaitForSingleObject(EmptySemaphoreHandle, INFINITE); 替换为 while(WAIT_TIMEOUT = WaitForSingleObject(EmptySemaphoreHandle, 300) printf("Producer wait for empty semaphore timeoutn&quo
35、t;); 4. 将Consumer函数中等待Full信号量的代码行 WaitForSingleObject(FullSemaphoreHandle, INFINITE); 替换为 while(WAIT_TIMEOUT = WaitForSingleObject(FullSemaphoreHandle, 300) printf("Consumer wait for full semaphore timeoutn"); 5. 启动调试新的生产者消费者项目,查看在虚拟机中输出的结果,验证信号量超时等待功能是否能够正常执行。如果有错误,可以调试内核代码来查找错误,然后在内核项目中修
36、改,并重复步骤1。 6. 如果超时等待功能已经能够正常执行,可以考虑将消费者线程修改为一次消费两个产品,来测试ReleaseCount参数是否能够正常使用。使用实验文件夹中NewConsumer.c文件中的Consumer函数替换原有的Consumer函数。 实验六:时间片轮转调度一、实验目的 调试EOS的线程调度程序,熟悉基于优先级的抢先式调度。 为EOS添加时间片轮转调度,了解其它常用的调度算法。 二、预备知识 阅读本书第5章中的第5.4节。重点理解EOS当前使用的基于优先级的抢先式调度,调度程序执行的时机和流程,以及实现时间片轮转调度的细节。实验内容3.1 准备实验3.2 阅读控制台命令“rr”相关的源代码没有时间片轮转调度时“rr”命令的执行效果3.3调试线程调度程序3.3.1 调试当前线程不被抢先的情况3.3.2 调试当前线程被抢先的情况3.4 为EOS添加时间片轮转调度(行时间片轮转调度时“rr”命令的执行效果)实验七:物理存储器与进程逻辑地址空间的管理一、实验目的 通过查看物理存储器的使用情况,并练习分配和回收物理内存,从而掌握物理存储器的管理方法。 通过查看进程逻辑地址空间的使用情况,并练
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 雇佣小工零工合同版
- 国有资产委托经营管理协议完整版
- 2024版工程物流与居间合同3篇
- 2024版新员工培训班操作手册:打造高效团队的关键
- 《速度和回声计算》课件
- 三年级上册英语书教育课件
- 《产业资本的运行》课件
- 《安全工程师》2024年阿拉善左旗预测密卷含解析
- 火车开了课件
- 企业高管聘用协议书标准范文
- 猜猜我有多爱你绘本 (2)
- 儿童通信知识教学(课堂PPT)
- 关于开发建设项目水土保持咨询服务费用计列的指导意见(保监[2005]22号)
- 人机工程评价标准
- 北医三院洁净实验室施工组织设计
- 储气罐日常检查维护保养记录表
- 小学五年级上册美术课件第9课小书签赣美版(16张)ppt课件
- 递等式计算(四年级上)
- 中级按摩师培训课件
- 钢丝绳、吊索具检查表(共3页)
- 文秘专业教学标准
评论
0/150
提交评论