操作系统实验报告
——OS Lab
班级:
姓名:
学号:
实验1 实验环境的使用
本次实验主要学习了OS Lab的基本使用方法;练习编译、调试了EOS操作系统内核以及EOS应用程序。
无论是EOS操作系统内核还是EOS应用程序,开始时它们都只是一些源代码文件。当编译器、链接器、软盘镜像编辑器等工具,对它们的源代码文件进行逐步转化后,它们就变成了可以在虚拟机(或者裸机)运行的EOS操作系统内核与EOS应用程序。
无论是EOS操作系统内核还是EOS应用程序,开始时它们都只是一些源代码文件。当编译器、链接器、软盘镜像编辑器等工具,对它们的源代码文件进行逐步转化后,它们就变成了可以在虚拟机(或者裸机)运行的EOS操作系统内核与EOS应用程序。
✧ 思考与练习
思考生成EOS SDK文件夹的目的和作用。查看EOS SDK文件夹中的内容,明白文件夹的组织结构和各个文件的来源和作用。查看EOS应用程序包含了SDK文件夹中的哪些头文件,是如何包含的?
答:操作系统通过向开发者提供SDK来开放其API,开发者在为操作系统编写应用程序时,通过使用SDK来调用API。如果要为操作系统开发应用程序,就需要首先获得操作系统的SDK。
SDK为了向开发者提供操作系统的API,往往会包含头文件、导入库文件和动态链接库文件。
头文件的主要作用是导出操作系统使用的一些数据类型(例如操作系统中使用的结构体类型)和API函数的声明,一般会被放在SDK中的Inc(Include)文件夹中
导入库文件(Import Library)是 根 据操作系统需要导出的API函数而生成的特定格式的二进制文件导入库文件。导入库文件的主要作用是告诉应用程序的可执行文件,其调用的API函数在操作系统中的地址,一般会被放在SDK中的Lib (Library)文件夹中。
动态链接库文件(Dynamic Link Library)是包含了操作系统导出的API函数的可执行代码的二进制文件。动态链接库文件的格式一般与可执行文件是相同的,只是不能直接执行,
答:操作系统通过向开发者提供SDK来开放其API,开发者在为操作系统编写应用程序时,通过使用SDK来调用API。如果要为操作系统开发应用程序,就需要首先获得操作系统的SDK。
SDK为了向开发者提供操作系统的API,往往会包含头文件、导入库文件和动态链接库文件。
头文件的主要作用是导出操作系统使用的一些数据类型(例如操作系统中使用的结构体类型)和API函数的声明,一般会被放在SDK中的Inc(Include)文件夹中
导入库文件(Import Library)是 根 据操作系统需要导出的API函数而生成的特定格式的二进制文件导入库文件。导入库文件的主要作用是告诉应用程序的可执行文件,其调用的API函数在操作系统中的地址,一般会被放在SDK中的Lib (Library)文件夹中。
动态链接库文件(Dynamic Link Library)是包含了操作系统导出的API函数的可执行代码的二进制文件。动态链接库文件的格式一般与可执行文件是相同的,只是不能直接执行,
一般会被放在SDK中的Bin(Binary)文件夹中。
在IDE 环境成功生成EOS的二进制文件后,会自动生成EOS SDK。IDE环境会首先新建一个SDK文件夹,然后将eos.h(导出API函数的声明)、eosdef.h(导出数据类型的定义)和error.h(导出错误码)三个头文件复制到SDK文件夹中的INC文件夹中,将生成的四个二进制文件都复制到BIN文件夹中(EOS SDK为了简单,将导入库文件也放入了BIN文件夹,而没有使用LIB文件夹)。这样,EOS SDK就具有了开发EOS应用程序所需的头文件、导入库文件和动态链接库文件。在编写EOS应用程序的源代码之前,必须首先获得EOS SDK文件夹。然后,在EOS应用程序的头文件eosapp.h中包含SDK/INC文件夹中的三个头文件。实际上,eosapp.h只需要包含eos.h文件就即可,因为在eos.h文件中已经包含了eosdef.h和error.h文件。
在IDE 环境成功生成EOS的二进制文件后,会自动生成EOS SDK。IDE环境会首先新建一个SDK文件夹,然后将eos.h(导出API函数的声明)、eosdef.h(导出数据类型的定义)和error.h(导出错误码)三个头文件复制到SDK文件夹中的INC文件夹中,将生成的四个二进制文件都复制到BIN文件夹中(EOS SDK为了简单,将导入库文件也放入了BIN文件夹,而没有使用LIB文件夹)。这样,EOS SDK就具有了开发EOS应用程序所需的头文件、导入库文件和动态链接库文件。在编写EOS应用程序的源代码之前,必须首先获得EOS SDK文件夹。然后,在EOS应用程序的头文件eosapp.h中包含SDK/INC文件夹中的三个头文件。实际上,eosapp.h只需要包含eos.h文件就即可,因为在eos.h文件中已经包含了eosdef.h和error.h文件。
实验2 操作系统的启动
跟踪调试EOS在PC机上从加电复位到成功启动的全过程,了解操作系统的启动过程查看EOS启动后的状态和行为,理解操作系统启动后的工作方式。
✧ 思考与练习
1. 为什么EOS操作系统从软盘启动时要使用boot.bin和loader.bin两个程序?使用一个可以吗?它们各自的主要功能是什么?如果将loader.bin的功能移动到boot.bin文件中,则boot.bin文件的大小是否仍然能保持小于512字节?
答:boot文件夹包含了两个汇编文件boot.asm和loader.asm。这两个文件生成的二进制文件boot.bin和loader.bin会被写入软盘镜像文件。操作系统启动时boot.bin和loader.bin引导软盘加载程序,二者缺一不可。使用Boot.bin的主要功能是引导软盘;loader.bin的主要功能是加载程序。如果把loader.bin功能移动到boot.bin程序中,必然导致程序规模扩大,可能使其大于512字节。
2. 软盘引导扇区加载完毕后内存中有两个用户可用的区域,为什么软盘引导扇区程序选择将loader.bin加载到第一个可用区域的0x1000处呢?这样做有什么好处?这样做会对loader.bin文件的大小有哪些限制。
答:首先用户只用两个可用区域,加载位置非此即彼。第一个可用用户区是低地址区,且空间大小比较小,适合容纳小文件,所以我们选择将占用空间小的loder.bin加载到第一用户区。
优点:由低地址开始,便于检索查。小文件占用小空间,节约资源。
限制:loader.bin文件必须小于1c00k.
答:boot文件夹包含了两个汇编文件boot.asm和loader.asm。这两个文件生成的二进制文件boot.bin和loader.bin会被写入软盘镜像文件。操作系统启动时boot.bin和loader.bin引导软盘加载程序,二者缺一不可。使用Boot.bin的主要功能是引导软盘;loader.bin的主要功能是加载程序。如果把loader.bin功能移动到boot.bin程序中,必然导致程序规模扩大,可能使其大于512字节。
2. 软盘引导扇区加载完毕后内存中有两个用户可用的区域,为什么软盘引导扇区程序选择将loader.bin加载到第一个可用区域的0x1000处呢?这样做有什么好处?这样做会对loader.bin文件的大小有哪些限制。
答:首先用户只用两个可用区域,加载位置非此即彼。第一个可用用户区是低地址区,且空间大小比较小,适合容纳小文件,所以我们选择将占用空间小的loder.bin加载到第一用户区。
优点:由低地址开始,便于检索查。小文件占用小空间,节约资源。
限制:loader.bin文件必须小于1c00k.
实验3 进程的创建
练习使用EOS API函数CreateProcess创建一个进程,掌握创建进程的方法,理解进程和程序的区别。
调试跟踪CreateProcess函数的执行过程,了解进程的创建过程,理解进程是资源分配的单位
调试跟踪CreateProcess函数的执行过程,了解进程的创建过程,理解进程是资源分配的单位
✧ 思考与练习
1. 在源代码文件NewTwoProc.c提供的源代码基础上进行修改,要求使用同时创建10个进程。提示:可以使用PROCESS_INFORMATION类型定义一个有10个元素的数组,每一个元素对应一个进程。使用一个循环创建10个子进程,然后再使用一个循环等待10个子进程结束,得到退出码后关闭句柄。
答:主要使用PROCESS_INFORMATION类型定义一个有10个元素的数组,每一个元素对应一个进程。使用一个循环创建10个子进程,然后再使用一个循环等待10个子进程结束,得到退出码后关闭句柄。
使用同时创建10个进程的原代码及注释如下:
1. 在源代码文件NewTwoProc.c提供的源代码基础上进行修改,要求使用同时创建10个进程。提示:可以使用PROCESS_INFORMATION类型定义一个有10个元素的数组,每一个元素对应一个进程。使用一个循环创建10个子进程,然后再使用一个循环等待10个子进程结束,得到退出码后关闭句柄。
答:主要使用PROCESS_INFORMATION类型定义一个有10个元素的数组,每一个元素对应一个进程。使用一个循环创建10个子进程,然后再使用一个循环等待10个子进程结束,得到退出码后关闭句柄。
使用同时创建10个进程的原代码及注释如下:
#include "EOSApp.h"
// main 函数参数的意义:
// argc-argv数组的长度,大小至少为1,argc-1为命令行//参数的数量。
//argv-字符串指针数组,数组长度为命令行参数个数+1。其中//argv[0]固定指向当前
//进程所执行的可执行文件的路径字符串,argv[1] 及其后面//的指针指向各个命令行参数。
//例如通过命令行内容 "a:\ -a -b" 启动进程//后, 的main函数的参数argc的值为3
//argv[0]指向字符串 "a:\",argv[1]指向参数字//符串"-a",argv[2]指向参数字符串"-b"。int main(int argc, char* argv[])
{
// 启动调试 EOS 应用程序前要特别注意下面的问题:// 1、如果要在调试应用程序时能够调试进入内核并显示对应//的源码,必须使用 EOS 核心项目编译生成完全版本的SDK
//文件夹,然后使用此文件夹覆盖应用程序项目中的SDK文件//夹,并且EOS核心项目在磁盘上的位置不能改变。
/
// main 函数参数的意义:
// argc-argv数组的长度,大小至少为1,argc-1为命令行//参数的数量。
//argv-字符串指针数组,数组长度为命令行参数个数+1。其中//argv[0]固定指向当前
//进程所执行的可执行文件的路径字符串,argv[1] 及其后面//的指针指向各个命令行参数。
//例如通过命令行内容 "a:\ -a -b" 启动进程//后, 的main函数的参数argc的值为3
//argv[0]指向字符串 "a:\",argv[1]指向参数字//符串"-a",argv[2]指向参数字符串"-b"。int main(int argc, char* argv[])
{
// 启动调试 EOS 应用程序前要特别注意下面的问题:// 1、如果要在调试应用程序时能够调试进入内核并显示对应//的源码,必须使用 EOS 核心项目编译生成完全版本的SDK
//文件夹,然后使用此文件夹覆盖应用程序项目中的SDK文件//夹,并且EOS核心项目在磁盘上的位置不能改变。
/
/2、在启动调试应用程序之前必须首先删除/禁用所有的断
//点,在断点中断 (int 3) 被命中后才能重新添加/启用断//点,否则启动调试会失败。
STARTUPINFO StartupInfo;
PROCESS_INFORMATION ProcInfo[10];
ULONG ulExitCode; // 子进程退出码
INT nResult = 0; //main函数返回值。0表示成功,非0
//表示失败。
int i,j;
//#ifdef _DEBUG
// __asm("int $3\n nop");
//#endif
printf("Create 10 processes and wait for the processes \n\n");
//使子进程和父进程使用相同标准句柄。
StartupInfo.StdInput = GetStdHandle(STD_INPUT_HANDLE);
StartupInfo.StdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
//点,在断点中断 (int 3) 被命中后才能重新添加/启用断//点,否则启动调试会失败。
STARTUPINFO StartupInfo;
PROCESS_INFORMATION ProcInfo[10];
ULONG ulExitCode; // 子进程退出码
INT nResult = 0; //main函数返回值。0表示成功,非0
//表示失败。
int i,j;
//#ifdef _DEBUG
// __asm("int $3\n nop");
//#endif
printf("Create 10 processes and wait for the processes \n\n");
//使子进程和父进程使用相同标准句柄。
StartupInfo.StdInput = GetStdHandle(STD_INPUT_HANDLE);
StartupInfo.StdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
StartupInfo.StdError = GetStdHandle(STD_ERROR_HANDLE); // createprocessa为一个应用程序同时创建10个子进程。
for(i =0; i < 10; i++)
if(CreateProcess("A:\\", NULL, 0, &StartupInfo,&ProcInfo[i]));
else {
for(j = 0; j < i; j++){
WaitForSingleObject(ProcInfo[j].ProcessHandle, INFINITE); // 得到并输出子进程的退出码。
GetExitCodeProcess(ProcInfo[j].ProcessHandle, &ulExitCode);
printf("\nThe process %d exit with %d.\n",j,ulExitCode); // 关闭不再使用的句柄。
CloseHandle(ProcInfo[j].ProcessHandle);
CloseHandle(ProcInfo[j].ThreadHandle);
for(i =0; i < 10; i++)
if(CreateProcess("A:\\", NULL, 0, &StartupInfo,&ProcInfo[i]));
else {
for(j = 0; j < i; j++){
WaitForSingleObject(ProcInfo[j].ProcessHandle, INFINITE); // 得到并输出子进程的退出码。
GetExitCodeProcess(ProcInfo[j].ProcessHandle, &ulExitCode);
printf("\nThe process %d exit with %d.\n",j,ulExitCode); // 关闭不再使用的句柄。
CloseHandle(ProcInfo[j].ProcessHandle);
CloseHandle(ProcInfo[j].ThreadHandle);
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论