xv6之旅-lab0 环境配置

256 阅读3分钟

前言

之前安装的ubuntu由于在各种各样的帖子引导下改动了太多配置文件,导致安装tools时总是安装失败,今天抽了一下午的时间又重新装了一遍ubuntu20.04,安装成功,可喜可贺!

ubuntu install

ubuntu的安装已经轻车熟路了,在此主要记录下一些关键步骤和遇到的问题。

  1. 刚安装好的ubuntu20.04没有网络,重新启动电脑后解决。

  2. 安装过程太慢可直接skip,进入ubuntu系统后,首先换源,可选aliyun,然后再进行软件更新

image.png

  1. 安装vmware tools,tar zxvf 将压缩包解压,进入文件夹,执行 ./vmware-install.pl程序,便可自适应大小和主机文件拖拽

tools install

打开terminal,执行

sudo apt-get install git build-essential gdb-multiarch qemu-system-misc gcc-riscv64-linux-gnu binutils-riscv64-linux-gnu 

克隆实验源码

git clone git://g.csail.mit.edu/xv6-labs-2021

进入源码文件夹,发现没有文件,切换到util分支,测试安装

cd xv6-labs-2021
git checkout util
make qemu

输出如下,说明安装成功

# ... lots of output ...
init: starting sh
$

pointer exercises

#include <stdio.h>
#include <stdlib.h>

void
f(void)
{
    int a[4];
    int *b = malloc(16);
    int *c; //注意:局部变量需要自己初始化,设为全局变量时编译器会自动帮你初始化。所以这里应为 int *c = NULL;
    int i;

    printf("1: a = %p, b = %p, c = %p\n", a, b, c);

    c = a;
    for (i = 0; i < 4; i++)
	a[i] = 100 + i;
    c[0] = 200;
    printf("2: a[0] = %d, a[1] = %d, a[2] = %d, a[3] = %d\n",
	   a[0], a[1], a[2], a[3]);

    c[1] = 300;
    *(c + 2) = 301;
    3[c] = 302;
    printf("3: a[0] = %d, a[1] = %d, a[2] = %d, a[3] = %d\n",
	   a[0], a[1], a[2], a[3]);

    c = c + 1;
    *c = 400;
    printf("4: a[0] = %d, a[1] = %d, a[2] = %d, a[3] = %d\n",
	   a[0], a[1], a[2], a[3]);

    c = (int *) ((char *) c + 1);
    *c = 500; //指向从a[1]的后3个字节至a[2]的前一个字节的地址,所以会影响a[1]a[2]的值
    printf("5: a[0] = %d, a[1] = %d, a[2] = %d, a[3] = %d\n",
	   a[0], a[1], a[2], a[3]);

    b = (int *) a + 1;
    c = (int *) ((char *) a + 1);
    printf("6: a = %p, b = %p, c = %p\n", a, b, c);
}

int
main(int ac, char **av)
{
    f();
    return 0;
}

运行结果:

image.png

Q1:

3[c]也修改了a[3]的值?

A1:

c语言语法允许使用逆序的下标,因为数组元素的访问是通过指针运算实现的,在内部它们都被翻译成*(c + 3)。所以c[3]和3[c]是等价的。

preparation

fork

创建一个子进程,拷贝创建时父进程的内存(指令和数据),所以子进程也会执行下方代码。返回子进程的pid,在子进程中返回0。

注意:二者内存不同,寄存器不同,只是创建时拷贝的内容相同,故在子进程修改变量不会影响父进程该变量

int pid = fork();
if(pid > 0){
printf("parent: child=%d\n", pid);
pid = wait((int *) 0); //等待子进程结束返回子进程pid,拷贝退出状态到传入的地址中,0表示父进程不关心结束状态
printf("child %d is done\n", pid);
} else if(pid == 0){
printf("child: exiting\n");
exit(0); //结束当前进程
} else {
printf("fork error\n");
}

an output

parent: child=1234
child: exiting
parent: child 1234 is done

redirect

0,1,2是console默认文件描述符

0代表标准输入,1代表标准输出,2代表标准错误输出

〉tmp1 将标准输出重定向到tmp1

2>&1将标准错误输出重定向到标准输出,即重定向到tmp1

故二者顺序不能颠倒

ls existing-file non-existing-file > tmp1 2>&1 #将存在的文件名和不存在文件的错误信息都输出到tmp1中