MIT·6.S081 操作系统学习笔记(一):概述

MIT·6.S081 操作系统学习笔记(一):概述

课程地址:https://www.bilibili.com/video/BV19k4y1C7kA

一、操作系统的目标

  • 对硬件抽象
  • 让许多应用程序复用硬件(可以同时运行多个软件,且不相互干涉)
  • 程序间的隔离
  • 程序间的共享 Sharing
  • 安全/权限系统 security
  • Performance
  • Range of OS,能够支持许多不同的功能

二、操作系统概述

用户空间User:运行软件的空间,例如vim,gcc,shell

Kernel:一个单独的特殊程序,管理计算机硬件资源,电脑启动时Kernel就启动
Kernel中提供了一些内置服务,例如

  • 文件系统(文件名等)访问磁盘
  • 对进程的管理
  • 内存分配

每个正在运行的程序都称作进程,其占用一定的内存
内核也提供对进程的某个操作的权限机制,访问控制

课程主要研究内核以及内核提供的接口

系统调用:内核提供的API,跳转到内核来完成某些操作

课程实验环境:QEMU模拟器,RISC-V微处理器指令集,xv6系统

Shell指令的本质:
例如mkdir指令,实际上它是存在于这台计算机上的一个可执行文件,一个程序,输入mkdir指令时会运行这个程序,来完成一些功能。

在一些pwn题中,拿到靶机的shell后会发现能够使用的指令很少,应该就是因为靶机削减了一些不必要的的指令程序。

三、实验

0x00 启动xv6

按6.S081的指导,下载好xv6的源代码后直接make qemu就可以了

使用的系统是ubuntu 20.04,执行make qemu时发现缺少了一些软件包,只需要使用apt指令进行下载安装即可。

成功启动xv6:

在这里插入图片描述

0x01 sleep

这个实验要求编写一个sleep程序并在xv6中使用
达到使得进程暂停用户所输入的时间数的目的。

我的代码:

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"

void main(int argc, char *argv[]) {
	
	if(argc <= 1) {
		fprintf(2, "sleep: invaild input.\n");
		exit(0);
	}

	int tick = atoi(argv[1]);
	if(tick < 0) {
		fprintf(2, "sleep: invaild input:%s\n", argv[1]);
		exit(0);
	}
	sleep(tick);
	exit(0);
}

按照实验要求,将sleep.c文件放入user文件夹

然后在Makefile的这个位置填写相关信息即可:

在这里插入图片描述

这里就是仅新增了一个条目:$U/_sleep\

效果如图所示:

在这里插入图片描述

0x02 pingpong

实验要求:

编写一个使用了unix系统调用的程序来实现两个进程之间的通信
父进程向子进程发送字节,子进程打印"<pid>: received ping",其中<pid>是进程ID
然后子进程在管道中写入字节发送给父进程并推出
父进程读取从子进程发送来的字节然后打印"<pid>: received pong"并推出

我的源代码:

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"

void main(int argc, char *argv[]) {
    int fd[2]; // fd[0]:out fd[1]:in
    int pid_s, pid;
    char message[20];
    if (pipe(fd) < 0) {
        fprintf(2, "pingpong: exception in pipe\n");
    }
    if ((pid_s = fork()) < 0) {
        fprintf(2, "pingpong: exception in fork");
    }
    else if (pid_s > 0) {
        pid = getpid();
        write(fd[1], "father", 7);
        sleep(1);
        while(read(fd[0], message, 4) <= 0);
        fprintf(2, "<%d> received pong %s\n", pid, message);
        close(fd[0]);
        close(fd[1]);
        exit(0);
    }else {
        pid = getpid();
        read(fd[0], message, 7);
        fprintf(2, "<%d>: received ping. %s\n", pid, message);
        write(fd[1], "son", 4);
        exit(0);
    }
}

0x03 Primes

我的源代码:

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"

typedef unsigned long long piper;

piper newPipe() {
    piper p;
    pipe(((int *)&p));
    return p;
}
void pipeWriteInt(piper pipe, int toWrite) {
    write(((int *)&pipe)[1], &toWrite, 4);
}
int pipeReadInt(piper pipe) {
    int toRet;
    int result = read(((int *)&pipe)[0], &toRet, 4);
    return result == 0 ? 0 : toRet;
}
void pipeClose(piper p) {
    close(((int *)&p)[1]);
    close(((int *)&p)[0]);
}
void pipeCloseRead(piper p) {
    close(((int *)&p)[0]);
}
void pipeCloseWrite(piper p) {
    close(((int *)&p)[1]);
}
int getPipeFirst(piper pipe) {
    int t = pipeReadInt(pipe);
    if(t == 0)exit(0);
    fprintf(2, "prime %d\n", t);
    return t;
}
void pipe_sender(piper lpipe, piper rpipe, int first) {
    int i;
    while((i = pipeReadInt(lpipe)) != 0) {
        if(i % first != 0) {
            pipeWriteInt(rpipe, i);
        }
    }
    pipeCloseRead(lpipe);
    pipeCloseWrite(rpipe);
}
void prime(piper lpipe) {
    pipeCloseWrite(lpipe);
    piper rpipe = newPipe();
    int first = getPipeFirst(lpipe);
    pipe_sender(lpipe, rpipe, first);
    if(fork() == 0) {
        prime(rpipe);
    }else {
        wait(0);
    }
}
void main(int argc, char *argv[]) {
    piper p = newPipe();
    int i;
    for(i = 2; i <= 35; i++) {
        pipeWriteInt(p, i);
    }
    if(fork() == 0) {
        prime(p);
    }else {
        pipeClose(p);
        wait(0);
    }
    exit(0);
}

0x04 find

观察ls.c文件,发现:

有一个stat结构体,有一个fstate(fd, &st)函数,能够让stat结构体得到相关文件的一些信息。
能够分辨出这是一个文件还是文件夹,如果是文件夹,则继续递归查找;如果是文件,则判断是否为我们想要的文件。

0x05 xargs

0x06 实验总结

  • fork()函数:创建一个新的进程,这个新的进程是完全复制当前进程的,且其也执行到父进程执行完毕fork()函数的位置
    并且,在父进程中,fork()函数返回子进程的id,而在子进程中,返回0,因此,可以利用这样的写法使得父进程与子进程的代码执行分离开:

    if(fork() == 0) {
        //子进程的代码
    }else {
        //父进程的代码
    }
    
  • pipe(int pip[2])函数:创建一个管道,管道可以理解成一种特殊的文件,它不存在于硬盘上,只存在于内存中。pipe函数的参数是一个长度为2的int数组,这个函数会为数组中的两个元素赋值,是两个文件描述符。其中,pip[0]是用于向管道中读取数据的文件描述符,pip[1]是用于向管道写入数据的文件描述符。管道机制可以用于进程之间的通信。

  • wait()函数:使一个进程停止,除非它的子进程消失,否则这个进程则会一直卡在执行到wait函数的位置。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值