实验四-Shelllab实验(csapp、计算机系统外壳实验)

这篇具有很好参考价值的文章主要介绍了实验四-Shelllab实验(csapp、计算机系统外壳实验)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

  一、准备工作

1、首先明确实验目的:

·总的来说就是让我们补充位于tsh.c中的七个函数,从而实现一个支持任务功能的shell。

因此在这儿将这七个函数分为两部分:

(1)实现完成内建命令(jobs、fg、bg、kill)的四个函数:

  实验四-Shelllab实验(csapp、计算机系统外壳实验)

接着再来了解一下tsh支持的四个内置命令:

·Quit:命令终止tsh进程

·jobs:命令列出所有后台进程

·bg:命令会向作业发送SIGCNOT信号来重启job,并作为后台作业运行,参数可以是PID或JID

·fg:同上,唯一区别是job以前台作业运行

(2)实现三个信号(SIGCHLD、SIGINT、SIGTSTP)的处理函数:

实验四-Shelllab实验(csapp、计算机系统外壳实验)

· 因此我们再来具体了解一下这三个信号:

 实验四-Shelllab实验(csapp、计算机系统外壳实验)

· 再来了解一下需要用到的辅助函数:

实验四-Shelllab实验(csapp、计算机系统外壳实验)

2、了解实验资源:

实验四-Shelllab实验(csapp、计算机系统外壳实验)

以上文件中,我们要实现的七个函数均在tsh.c中,tshref是参考文件。图中的txt文件均是测试文件。

3、如何比对我们实现的同时是否正确:

(1)首先执行make指令编译tsh.c得到可执行文件tsh:

 实验四-Shelllab实验(csapp、计算机系统外壳实验)实验四-Shelllab实验(csapp、计算机系统外壳实验)

 (2)然后就执行make rtest01 ;make test01进行比对,如果我们的执行结果与参考结果一致,则实现正确,如下:

实验四-Shelllab实验(csapp、计算机系统外壳实验)

否则不正确,如下:

实验四-Shelllab实验(csapp、计算机系统外壳实验)

(输出不一致,说明功能未成功实现)

二、具体实现

  1. trace01 ->  正确终止EOF:

     实验四-Shelllab实验(csapp、计算机系统外壳实验)

    可成功运行。

     2.trace 02 ->实现内置的quit

  1. 分析 :

实验四-Shelllab实验(csapp、计算机系统外壳实验)

 trace02.txt文件中只有quit,WAIT两条命令。

先执行看看:

实验四-Shelllab实验(csapp、计算机系统外壳实验)

可以看到无法正常终止,因为tsh的quit内置命令还未编写,所以不能正常退出

因此需要我们实现终止命令(quit。 

(2)实现之前我们来了解eval()与execve()执行流程和fork()多进程运行方式

  程序会首先执行 eval(),在 eval中进行判断(使用buildin_cmp()函数),如果发现命令不是内置命令,则会调用 fork()函数来新建一个子进程,在子进程中调用 execve()函数通过 argv[0]来寻找路径,并在子进程中运行路径中的可执行文件,如果找不到可执行文件,则说明命令为无效命令,输出命令无效,并用 exit(0)结束该子进程即可。

(3)实现quit:

 ·补齐文件tsh.c中的函数eval()函数和函数builtin_cmd()与quit相关的部分

 · 实现思路首先从命令中提取参数,然后判断是否为内置命令,如果为内置命令,则直接在当前进程执行即可;如果不是内置命令,则需要新建一个子进程,并利用 execve 来通过参数给出的路径寻找出可执行文件并在子进程中执行,如果找不到该可执行文件,则输出命令未找到,并结束子进程。

· 代码:

  1. 首先是eval函数

实验四-Shelllab实验(csapp、计算机系统外壳实验)

  2.然后是判断是否为内置命令的函数builtin_cmd()

实验四-Shelllab实验(csapp、计算机系统外壳实验)

 (4)验证:因为tset03功能是运行一个前台job,并且也是以quit终止,因此一起验证:

可以看出,成功!

实验四-Shelllab实验(csapp、计算机系统外壳实验)实验四-Shelllab实验(csapp、计算机系统外壳实验)

3 . trace04 -->实现eval()的后台作业(BK job)管理功能

(1)思路:

·在原有eval函数基础之上添加将作业添加至后台作业管理的函数使用addjobs())。

·加以信号的阻塞和取消阻塞。

***(注意)

那为什么在这里要控制信号的阻塞呢?

答:总的来说,为了保证处理程序回收终止的子进程(delete job)在父进程(addjob)之后进行,否则父子进程之间会出现经典的同步错误---竞争。

详细理解:因为当父进程创建一个子进程时,它就会将这个子进程添加到作业列表(addjobs)。当父进程在SIGCHLD处理程序中回收一个僵尸子进程时,就要从作业列表中删除子进程。理想状态下,这个过程很正确,但是往往真实的运行情况下,会出现问题,如下图:

实验四-Shelllab实验(csapp、计算机系统外壳实验)

 总结来说,就是会出现在addjob之前调用deletejob,导致出错。

***

(2)具体实现:

 1.首先使用一个标记符号(bg):

实验四-Shelllab实验(csapp、计算机系统外壳实验)

 2.因为要分析传入指令是否要在后台执行进程,因此要补充分析命令的函数builtin_cmd():

实验四-Shelllab实验(csapp、计算机系统外壳实验)

 3.接着在eval中进行判断是否为后台进程:

实验四-Shelllab实验(csapp、计算机系统外壳实验)

 实验四-Shelllab实验(csapp、计算机系统外壳实验)

 4.再将waitfg()函数补充完整:

实验四-Shelllab实验(csapp、计算机系统外壳实验)

让父进程正确地等待。

   5.接下来实现信号的控制,这里使用sigprocmask()函数显式地阻塞和取消阻塞

(1)初了解:

实验四-Shelllab实验(csapp、计算机系统外壳实验)

(2)在eval()中的使用:

实验四-Shelllab实验(csapp、计算机系统外壳实验)

 上述图片的操作中,我们就保证了父进程先addjob(),然后子进程再deletejob();

6.接下来实现对应的sigcld_handler()以释放僵尸的子进程:

实验四-Shelllab实验(csapp、计算机系统外壳实验)

详情看红框操作。

综上,我们的addjobs就成功实现了!

7.验证:

实验四-Shelllab实验(csapp、计算机系统外壳实验)

通过!

4. trace05 -->处理jobs内置命令:

 实验四-Shelllab实验(csapp、计算机系统外壳实验)

(1)思路:直接调用自带的listjobs()方法,就是在原有builtin_cmd函数中添加一个判断函数,如果参数是jobs,则执行listjobs函数的功能(即将所有的作业打印出来)

(2)实现:

实验四-Shelllab实验(csapp、计算机系统外壳实验)

(3)测试:

实验四-Shelllab实验(csapp、计算机系统外壳实验)

成功!

5.trace06、trace07 ->处理SIGINT信号

实验四-Shelllab实验(csapp、计算机系统外壳实验)实验四-Shelllab实验(csapp、计算机系统外壳实验)

(1)目的:

要实现的功能是:trace06->将SIGINT信号转发到前台作业;

                             trace07->仅仅将SIGINT信号转发到前台作业;

因此这里放在一起实现。

SIGINT:来自键盘的中断(ctrl+c)

(2)文档提示:

实验四-Shelllab实验(csapp、计算机系统外壳实验)

 综上,就是说要保证ctrl+c只会终止你当前的shell进程,而不会影响其他进程。

(3)实现:

   根据文档中的解决方法,我们来一步步实现。

1.首先更改一下eval函数,在其中调用setpgid(0,0):

实验四-Shelllab实验(csapp、计算机系统外壳实验)

添加了红框中的代码,解释也在注释中。

2.更改信号处理函数sigint_handler(),实现转发到前台作业的操作(包含前台作业的进程组)

 实验四-Shelllab实验(csapp、计算机系统外壳实验)

3.还要修改sigchld_handler()函数:

****

为什么呢?

   答:是为了区分进程终止的原因(符合测试文件)(后边也会用到)

    1.是正常终止(exit或return)

     2.还是因为收到其他信号如:SIGINT而终止。(这里我们是收到SIGINT信号终止的)

****

修改如下:

实验四-Shelllab实验(csapp、计算机系统外壳实验)

综上,就成功实现!

(4)测试:

实验四-Shelllab实验(csapp、计算机系统外壳实验)实验四-Shelllab实验(csapp、计算机系统外壳实验)

成功!

6、Trace08 -> 仅仅将SIGSTP(ctrl+z)转发到前台作业(与上一题实现大同小异)

实验四-Shelllab实验(csapp、计算机系统外壳实验)

(1)因此我们就直接实现其信号处理函数sigtstp_handler():

实验四-Shelllab实验(csapp、计算机系统外壳实验)

(2)依旧来修改一下sigchld_handler()函数。区分终止/停止。

思路:因此在上一题的基础上加上对于SIGTSTP(ctrl+z)的判断和信息显示。

如下:

实验四-Shelllab实验(csapp、计算机系统外壳实验)

 ·加了红框框的内容,实现。

·还要加多一个WUNTRACED(见绿框),变成WNOHANG | WUNTRACED。

***

为什么呢?

WNOHANG:挂起调用进程,直到有子进程终止。

WUNTRACED:挂起调用进程,直到等待集合中的一个进程变成已终止或者被停止。

WNOHANG | WUNTRACED:等待集合中的子进程都没有被停止或终止,则返回值为0;如果有一个停止或终止,则返回值为该子进程的PID。

可以理解为WNOHANG接收终止,WUNTRACED接收停止。

两个合在一起就是接收终止和停止(ctrl+z和ctrl+c)。

***

(3)测试:

实验四-Shelllab实验(csapp、计算机系统外壳实验)

成功!

7.trace 09 ---> 实现进程内置命令bg

     bg <job>:命令会向一个已经停止的job发送SIGCNOT信号来重启这个job,并作为后台作业运行,参数可以是PID或JID

(1)首先是完成识别命令:

要将bg命令添加到识别命令的函数builtin_cmd()中:

   实验四-Shelllab实验(csapp、计算机系统外壳实验)

2接下来实现其处理函数:

·修改do_bgfg()方法

实验四-Shelllab实验(csapp、计算机系统外壳实验)

3测试:

实验四-Shelllab实验(csapp、计算机系统外壳实验)

成功!

8 .trace 10 ---> 实现进程内置命令fg(与上一题差不多)

       fg <job>:将一个已停止或正在运行的后台作业更改为正在前台运行的作业

(1)老方法,先往builtin_cmd()方法添加内容:

实验四-Shelllab实验(csapp、计算机系统外壳实验)

(2)然后往do_bgfg()函数中加入相关处理:

实验四-Shelllab实验(csapp、计算机系统外壳实验)

需要注意的一点就是红框所圈的内容,也是与BG实现区别的地方。

(3)测试:

实验四-Shelllab实验(csapp、计算机系统外壳实验)

成功!

9 .trace 11 ---> 将SIGINT转发给前台进程组中的每个进程

     trace 12 ----> 将SIGSTP转发给前台进程组中的每个进程

   这两个实验在之前的trace06-trace07的分析中已经实现了,因此我们直接执行即可:

(1)sigint_handler()函数:

实验四-Shelllab实验(csapp、计算机系统外壳实验)

(2)sigtstp_handler()函数:

 实验四-Shelllab实验(csapp、计算机系统外壳实验)

3测试:

实验四-Shelllab实验(csapp、计算机系统外壳实验)

成功!

10.trace13 -->重新启动进程组中每个已经停止的进程

  1. 首先回顾一下我们之前有关唤醒进程的操作:

在trace09和trace10中对BG和FG的处理中(do_bgfg()函数),我们是有条件地唤醒进程,并将之修改为对应需要的状态(前台或后台),如下图:

实验四-Shelllab实验(csapp、计算机系统外壳实验)

继续分析

· 因为此时需要唤醒所有停止的进程,因此要将唤醒函数kill(pid,SIGCONT)的第一个参数改为-pid,因为当其第一个参数<0时,kill就会将SIGCONT信号传递给整个进程组。

· 因为在FG中,有一步是需要等待当前的前台进程完成之后,才会唤醒进程组中的进程,所以为了保证唤醒所有进程,就要去掉FG中,job->state == ST才传递SIGCONT信号的判断,因为当前运行进程可能没有停止(ST),但是进程组中是有停止的,进程组中停止的这些也需要被唤醒

(2)综上,我们得到以下实现:

实验四-Shelllab实验(csapp、计算机系统外壳实验)

(3)测试:

实验四-Shelllab实验(csapp、计算机系统外壳实验)

成功!

11.trace14- 简单的错误处理(就是处理输入未实现的命令、fg、bg参数不正确等错误情况)

(1)先运行看看怎么处理:

实验四-Shelllab实验(csapp、计算机系统外壳实验)

从上图看出一共有五种处理方式,因此我们在do_bgfg()中进行对应的处理即可。

(2)处理:

·第一个错误:Command not found,未实现的命令。

我们再次回顾一下shell的执行流程:程序会首先执行 eval(),在 eval中进行判断(使用buildin_cmp()函数),如果发现命令不是内置命令,则会调用 fork()函数来新建一个子进程在子进程中调用 execve()函数通过 argv[0]来寻找路径,并在子进程中运行路径中的可执行文件,如果找不到可执行文件,则说明命令为无效命令。因此我们在此处加入输出语句即可,如下图:

实验四-Shelllab实验(csapp、计算机系统外壳实验)

· 第二个错误是:fg command requires PID or %jobid argument,fg命令时没有传入pid或jid。

  因此在do_bgfg()中实现:

实验四-Shelllab实验(csapp、计算机系统外壳实验)

·第三个错误是:fg: argument must be a PID or %jobid,传入了pid或jid,但是不符合规范(pid或jid必须为数字)。

处理:

实验四-Shelllab实验(csapp、计算机系统外壳实验)

·第四个错误是:No such process,通过传入的pid找不到对应的作业(job=null)

处理:

实验四-Shelllab实验(csapp、计算机系统外壳实验)

·第五个错误No such job通过传入的jid找不到对应的job(job=null)

实验四-Shelllab实验(csapp、计算机系统外壳实验)

此外,我们发现还有一行(绿色框所圈),这里我们和trace15

一起解决。所以接下来看一下trace15.

12. trace15-->所有命令一起运行

(1)先make rtest一下,看看缺什么:

 实验四-Shelllab实验(csapp、计算机系统外壳实验)

如上图,缺少这两条消息的处理,因此我们要加上处理:

那么首先查看一下文件trace15.txt,看看是因为什么信号出现这种情况:

实验四-Shelllab实验(csapp、计算机系统外壳实验)可以看到,INT信号将job10终止。

实验四-Shelllab实验(csapp、计算机系统外壳实验) TSTP信号将job1中断。

因此我们就在终止信号处理函数sihchld_handler()中进行判断处理,并输出上述错误信息:

处理:

实验四-Shelllab实验(csapp、计算机系统外壳实验)

 实验四-Shelllab实验(csapp、计算机系统外壳实验)

OK,完成!

(3)测试:

Trace14:

实验四-Shelllab实验(csapp、计算机系统外壳实验)

成功!

Trace15(测试所有命令):

实验四-Shelllab实验(csapp、计算机系统外壳实验)

成功!

13. trace16 -->测试shell是否能够处理来自其他进程而不是终端的SIGTSTP和SIGINT信号。

(1)查看一下trace16.txt:

实验四-Shelllab实验(csapp、计算机系统外壳实验)

可以看到测试文件的操作是:

     测试shell能否处理来自mystop和myint的SICINT和SINTSTP信号。

(2)测试:

实验四-Shelllab实验(csapp、计算机系统外壳实验)

 分析:可以看到上图中小旗帜标识的位置,在jobs执行内置命令之后,对于SIGINT和SINTSTP信号均做出了处理。成功!

ps:trace16其实还有点不太清楚。文章来源地址https://www.toymoban.com/news/detail-454816.html

最后贴上所有代码:

void eval(char *cmdline) //加载且执行命令
{
    char *argv[MAXARGS];        /* 参数列表execve() */
    char buf[MAXLINE];          /* 保存修改的命令行 */
    int bg;                     /* 这个作业应该在后台进行? */
    pid_t pid;                  /* 进程id*/
    strcpy(buf,cmdline);
    bg = parseline(buf,argv);
    if(argv[0] == NULL)
        return;                 /* 忽略空命令 */

    sigset_t mask_all,mask_one,prev_one;
    if(!builtin_cmd(argv)){
        sigfillset(&mask_all);  /* 保存当前的阻塞信号集合(blocked位向量) */
        sigemptyset(&mask_one); //初始化mask_one为空集
        sigaddset(&mask_one,SIGCHLD);//添加SIGCHLD到mask_one中
        //以上三句保存了当前的已阻塞信号集合

        sigprocmask(SIG_BLOCK,&mask_one,&prev_one);         /* 添加mask_one中的信号到信号集合(blocked位向量),从而父进程保持SIGCHLD的阻塞*/
        if((pid = fork()) == 0){    /* 子程序运行用户作业 */

            sigprocmask(SIG_SETMASK,&prev_one,NULL); /* 因为子进程继承了它们父进程的被阻塞集合,所以在调用execve之前,必须
                                                         解除子进程对SIGCHLD的阻塞,避免子进程fork出来的进程无法被回收*/


       if(setpgid(0,0) < 0){               /* 把子进程放到一个新进程组中,该进程组ID与子进程的PID相同。这将确保前台进程组中只有一个进程,即shell进程。*/
        printf("setpgid error");
        exit(0);
    }
            if(execve(argv[0],argv,environ) < 0){
                printf("%s: Command not found.\n",argv[0]);
       //第一个错误处理,直接在这里进行提示信息输出
                exit(0);
            }
        }
        
        sigprocmask(SIG_BLOCK,&mask_all,NULL);   /* 恢复信号集合(blocked位向量) */
        addjob(jobs,pid,bg==1 ? BG : FG,cmdline); /* 将子任务添加到任务列表中 */
        sigprocmask(SIG_SETMASK,&prev_one,NULL);  /* 解除子进程对SIGCHLD的阻塞 */
        /* 这样子sigchld_handler处理程序在我们将其添加到工作队列
            中之前是不会运行的。因为直到addjob()之后,我们才解除对SIGCHLD的阻塞
         */


        /* 父任务等待前台任务结束 */
        if (!bg){ //如果不是后台进程,就等待当前的前台进程
            waitfg(pid);
        }else{  /* 否则就是后台进程,开始在后台工作 */
            printf("[%d] (%d) %s",pid2jid(pid),pid,cmdline);
        }
    }

    return;

}
/* 
 * builtin_cmd - If the user has typed a built-in command then execute
 *    it immediately.  
 */
int builtin_cmd(char **argv) //判断当前命令是否为内置命令
{
   if(!strcmp(argv[0],"quit")) //如果是内置命令quit
        exit(0);               //就结束当前进程
   if(!strcmp(argv[0],"jobs")){    /* jobs内置指令 */
        listjobs(jobs);
        return 1;
    }
   if(!strcmp(argv[0],"&")) /* 忽略单& */
        return 1;  //然后返回1,因为如果一个命令以&结尾,shell应该在后台运行它,否则在前台运行;

  if(!strcmp(argv[0],"bg")){      /* bg内置指令 */
    do_bgfg(argv);
    return 1;
}
   if(!strcmp(argv[0],"fg")){      /* fg内置指令 */
    do_bgfg(argv);
    return 1;
  }

    return 0;     /* 不是一个内置命令 */
}
void do_bgfg(char **argv) 
{

    pid_t pid;                      /* 进程id */
    int jid;                        /* job的id */
    struct job_t * job;
    if (argv[1] == NULL){
        printf("%s command requires PID or %%jobid argument\n",argv[0]);
        return;
    }
    //第二个错误是没有传入pid或者jid(为空),就报错并返回

    if (argv[1][0] == '%'){   /* 如果输入的是jid(作业) */
        if(argv[1][1] < '0' || argv[1][1] >'9'){
            printf("fg: argument must be a PID or %%jobid\n");
            return;
        }
   //第三个错误命令是传入了,但是传入的数据不是不符合pid或jid的规范(输入必须为数字)
   //在这里判断并输出错误信息:fg: argument must be a PID or %%jobid\n
        jid = atoi(argv[1]+1);
        job = getjobjid(jobs,jid);//通过jid找到需要执行的job
        if(job == NULL){
            printf("%%%d: No such job\n",jid);
            return;
        }
   //第四个错误就是通过jid找到的job==null,因此“NO such job”
        pid = job->pid;
    }else{                              /* 给的是pid */
        if(argv[1][0] < '0' || argv[1][0] >'9'){
            printf("bg: argument must be a PID or %%jobid\n");
            return;
        }
        pid = atoi(argv[1]);
        job = getjobpid(jobs,pid);
        if(job == NULL){
            printf("(%d): No such process\n",pid);
            return;
        }
//第五个错误就是通过jid找到的job==null,因此“NO such job”
        jid = job->jid;
    }
    if(pid > 0){
        if(!strcmp(argv[0],"bg")){          /* bg内置指令 */
            printf("[%d] (%d) %s",jid,pid,job->cmdline);
            job->state = BG;                /* 更改状态 */
            kill(-pid,SIGCONT);              /* 传递SIGCONT信号给进程组中的所有进程 */
            
        }else
        if(!strcmp(argv[0],"fg")){          /* fg内置指令 */
            job->state = FG;                /* 更改状态 */
            kill(-pid,SIGCONT);             /* 传递SIGCONT信号给进程组中的所有进程 */
            waitfg(pid);                    /* 等待前台job完成 */
        }
    }

    return;
}
/* 
 * waitfg - 阻塞,直到进程的pid不再是前台进程
 */
void waitfg(pid_t pid)
{
     /* 唯一的前台作业结束后,被sigchld_handler回收,deletejob()后,jobs列表中就没有前台作业了,
        循环fpgid(..)
    */
    while(pid==fgpid(jobs)){
        sleep(0);
    }
    return;
}
/* 
 * sigchld_handler - 每当子作业终止(变成僵尸),或者因为收到SIGSTOP或SIGTSTP信号而停止时,
 * 内核就向shell发送SIGCHLD。该处理程序获取所有可用的僵尸子进程,
 * 但不等待任何其他当前运行的子进程终止。
 */
void sigchld_handler(int sig) 
{
    int olderrno = errno;
    sigset_t mask_all,prev_all;
    pid_t pid;
    int status;

    sigfillset(&mask_all);                          /* 保存当前的信号集合(blocked位向量) */
    while((pid = waitpid(-1,&status,WNOHANG | WUNTRACED)) > 0){    /* WNOHANG:非阻塞的 */
        /* 通过调用exit或者一个返回(return)正常终止 */
        if(WIFEXITED(status)){
            sigprocmask(SIG_BLOCK,&mask_all,&prev_all); /* 恢复信号集合(blocked位向量) */
            deletejob(jobs,pid);     
            sigprocmask(SIG_SETMASK,&prev_all,NULL);                   
        }
        /* 子进程是因为一个未被捕获的信号终止的(SIGINT) */
        if(WIFSIGNALED(status)){
            int jid = pid2jid(pid);
            printf("Job [%d] (%d) terminated by signal %d\n",jid,pid,WTERMSIG(status));
            deletejob(jobs,pid);/* 终止就删除pid的job */
        }
        /* 引起返回的子进程当前是停止的(SIGTSTP) */
        if(WIFSTOPPED(status)){
            struct job_t * job = getjobpid(jobs,pid);
            int jid = pid2jid(pid);
            printf("Job [%d] (%d) stopped by signal %d\n",jid,pid,WSTOPSIG(status));
            job->state = ST;			/* 状态设为停止(ST) */
        }
        
    }
    errno = olderrno;

    return;
}
/* 
 * sigint_handler - 当用户在键盘上键入ctrl-c时,内核向shell发送一个SIGINT。抓住它并把它发送到前台工作。
 */
void sigint_handler(int sig) 
{
    pid_t pid = fgpid(jobs);	/* 获取前台进程id */
    if(pid > 0){
        kill(-pid,sig);     	/* 转发信号sig给进程组|pid|中的每个进程 */
    }
    return;
}
/*
 * sigtstp_handler - 每当用户在键盘上键入ctrl-z时,内核就向shell发送一个SIGTSTP。捕获它并通过向它发送SIGTSTP来挂起前台作业。
 */
void sigtstp_handler(int sig) 
{
    pid_t pid = fgpid(jobs);    /* 获取前台进程id */

    if(pid > 0){
        kill(-pid,sig);         /* 转发信号sig给进程组|pid|中的每个进程 */
    }
    return;
}

到了这里,关于实验四-Shelllab实验(csapp、计算机系统外壳实验)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 计算机操作系统实验:进程调度实验

    前言 二、实验目的 三、实验要求 四、实验原理 五、实验过程 六、代码详解 总结 计算机操作系统是管理计算机硬件和软件资源的核心软件,它负责为用户提供一个友好、高效、安全的使用环境。进程调度是操作系统的一个重要功能,它决定了进程在处理器上的执行顺序和时

    2024年02月07日
    浏览(57)
  • 计算机系统实验2:炸弹实验bomb

    炸弹实验 本次实验为熟悉汇编程序及其调试方法的实验。 实验内容包含2个文件bomb(可执行文件)和bomb.c(c源文件)。 实验主题内容为:程序运行在linux环境中。程序运行中有6个关卡(6个phase),每个phase需要用户在终端上输入特定的字符或者数字才能通关,否则会引爆炸

    2023年04月26日
    浏览(42)
  • 计算机系统实验二——bomblab(炸弹实验)

    bomblab 使用gdb工具 反汇编 出汇编代码,结合c语言文件找到每个关卡的 入口函数 。然后分析汇编代码,分析得到每一关的通关密码。 进一步加深对linux指令的理解,对 gdb调试 的一些基本操作以及高级操作有所了解。 熟悉汇编程序,懂得如何利用汇编程序写出C语言程序伪代

    2023年04月20日
    浏览(46)
  • 【BinaryBomb实验】计算机系统基础

    实验原理与内容 一个“binary bombs”(二进制炸弹,下文将简称为炸弹)是一个Linux可执行C程序,包含了7个阶段(phase1~phase6和一个隐藏阶段)。炸弹运行的每个阶段要求学生输入一个特定的字符串,若的输入符合程序预期的输入,该阶段的炸弹就被“拆除”,否则炸弹“爆炸

    2024年02月07日
    浏览(44)
  • 计算机系统基础实验 AttackLab

    本文是作者的作业备份,仅作参考,不可照搬抄袭! 本实验分为五个阶段,ctarget的三个使用的是CI(code-injection),rtarget的两个阶段使用的是ROP(return-oriented-programming),如表1所示 ctarget和rtarget都是用getbuf函数从标准输入读入字符串,getbuf函数定义如下: 函数 Gets 类似于标

    2024年02月09日
    浏览(44)
  • 计算机系统装配与集成实验

    1.通过学习、查阅/寻找资料,培养学生获取有关计算机组装的技术、工艺及测试方法、驱动程序的能力。 2.培养学生计算机硬件系统的拆卸、安装、故障排除,操作系统安装与设置,驱动程序加载,技术指标测试等方面的能力,获得计算机系统维护的基本训练。 3.培养学生遵

    2024年02月11日
    浏览(49)
  • 计算机视觉实验:人脸识别系统设计

    设计 计算机视觉目标识别系统,与实际应用有关(建议:最终展示形式为带界面可运行的系统),以下内容选择其中一个做。 1. 人脸识别系统设计 (1) 人脸识别系统设计(必做):根据课堂上学习的理论知识(包括特征提取、分类器设计),设计一个人脸识别系统,该系统具

    2024年02月14日
    浏览(55)
  • 深入理解计算机系统AttackLab实验

    实验目的与要求 强化机器级表示、汇编语言、调试器和逆向工程等方面基础知识,并结合栈帧工作原理实现简单的栈溢出攻击,掌握其攻击的基本方式和原理,进一步为编程过程中应对栈溢出攻击打下一定的基础。 理解缓冲区的工作原理和字符填充过程及其特点。对于无边

    2024年02月04日
    浏览(46)
  • 计算机系统(3) 实验一:MIPS64位指令集实验

    一、   实验目标: 了解WinMIPS64的基本功能和作用; 熟悉MIPS指令、初步建立指令流水执行的感性认识; 掌握该工具的基本命令和操作,为流水线实验作准备。 二、实验内容 按照下面的实验步骤及说明,完成相关操作 记录实验过程的截图 : 1)下载WinMIPS64;运行样例代码并

    2024年02月07日
    浏览(43)
  • 计算机组成原理实验二 存储系统预习报告

    掌握静态随机存储器 RAM  工作特性及数据的读写方法。 基于信号时序图,了解读写静态随机存储器的原理。 1、阅读实验指导书,然后回答问题。 实验所用的静态存储器由一片 6116( 2K*8bit  )构成(位于MEM 单元),6116 有三个控制线:CS 表示( 片选线  ) ,   OE 表示

    2023年04月15日
    浏览(62)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包