MIT6.828LAB1 (4)

本文介绍了C语言中指针的概念和在BootLoader环境下的应用,包括内存地址操作、C语言指针示例以及链接地址设置对引导加载程序的影响。作者通过练习和实验,强调了对指针深入理解的重要性。
摘要由CSDN通过智能技术生成

LAB1_Part2 The Boot Loader


前言

记录一下自己的学习过程
实验内容翻译:
https://gitee.com/cherrydance/mit6.828
该翻译仅供参考

练习4

练习4. 请阅读有关在C语言中使用指针的资料。C语言的最佳参考资料是Brian Kernighan和Dennis Ritchie所著的《C程序设计语言》(通常称为“K&R”)。
请阅读K&R的5.1节(指针和地址)到5.5节(字符指针和函数)。然后下载pointers.c的代码,运行它,并确保你理解所有打印出的值的来源。特别是要确保你理解打印行1和6中指针地址的来源,以及打印行2到4中所有值是如何得到的,以及为什么打印行5中的值似乎被破坏了。
在C语言中,还有其他关于指针的参考资料(例如,Ted Jensen的教程引用了大量K&R的内容),尽管没有被强烈推荐。
警告:除非你已经对C语言非常熟悉,否则不要跳过或仅是浏览这个阅读练习。如果你对C语言中的指针不真正理解,那么在接下来的实验中你将遭受难以言喻的痛苦和困苦,最终只能通过艰难的方式来理解它们。相信我们,你不想知道什么是“艰难的方式”。

先下载pointers.c的代码https://pdos.csail.mit.edu/6.828/2018/labs/lab1/pointers.c

	int a[4];
    int *b = malloc(16);
    int *c;
    int i;
    printf("1: a = %p, b = %p, c = %p\n", a, b, c);

打印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]);

将指针a赋值给c,所以c和a指向同一块地址
四个值分别为a[0] =200, a[1] = 101, a[2] = 102, a[3] = 103

    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[1]的值改为300,*(c+2)=c[2],3[c]=c[3]
所以四个值分别为a[0] =200, a[1] = 300, a[2] = 301, a[3] = 302

    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=c+1,其实就是将指针c从a[0]的地址变成指向a[1]
所以四个值分别为a[0] =200, a[1] = 400, a[2] = 301, a[3] = 302

    c = (int *) ((char *) c + 1);
    *c = 500;
    printf("5: a[0] = %d, a[1] = %d, a[2] = %d, a[3] = %d\n",
	   a[0], a[1], a[2], a[3]);

将指针c指向的int强制转换char,再加1,则它指的位置后移一个字节,再把指针转换回int*。首先我们要知道存储方式是小端存储。变化如下图所示:
在这里插入图片描述
所以四个值分别为a[0] =200, a[1] = 128144, a[2] = 256, a[3] = 302

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

b的地址为a加4,一个int大小的值,c为a+1。运行结果如下图所示:
在这里插入图片描述

练习5

在再次跟踪引导加载程序的前几条指令时,找到如果引导加载程序的链接地址设置错误会导致第一条指令“中断”或发生其他错误的指令。然后在boot/Makefrag中将链接地址更改为错误的值,运行make clean,使用make重新编译实验,并再次跟踪进入引导加载程序以查看发生了什么。之后不要忘记将链接地址改回,并再次运行make clean!

根据实验前文描述“在boot/Makefrag中传递"-Ttext 0x7C00"参数给链接器来设置链接地址”,我们得到练习需要更改的地方,将0x7c00改为0x7d00,运行make clean再make。使用gdb跟踪程序。首先查看boot.asm文件,发现地址由之前的0x7c00变成了0x7d00。
在这里插入图片描述

由于bios将bootloader默认加载在0x7c00处,所以还是在0x7c00设置断点。
我们使用si单步执行,可以发现前几条命令依然正确执行
在执行到命令ljmp $0x8,$0x7d32之后就发生了错误
在这里插入图片描述
而且在另一个终端可以看到make qemu-gdb发生了严重错误。
在这里插入图片描述

练习6

我们可以使用GDB的x命令来检查内存。GDB手册中有详细的说明,但现在只需要知道x/Nx ADDR命令会打印在ADDR处的N个字的内存内容。(请注意,命令中的两个’x’都是小写。)警告:字的大小并没有统一的标准。在GNU汇编中,一个字是两个字节(xorw中的’w’代表字,表示2个字节)。
重置机器(退出QEMU/GDB并重新启动它们)。在BIOS进入引导加载程序的位置,检查0x00100000处的8个字的内存内容,然后在引导加载程序进入内核的位置再次检查。为什么它们是不同的?在第二个断点上有什么内容?(你不需要真正使用QEMU来回答这个问题,只需思考即可。)

在这之前先将链接地址改回0x7c00,make clean之后make。
根据要求打印出0x00100000处的内容,bios进入bootloader是0x7c00,进入内核的地址我们在之前的实验中已经得到,如果不记得了可以打开kern.asm文件,里面可以看到内核的开始地址是0x10000c。

在这里插入图片描述
我们打开kern.asm文件,查看开头几行,发现后面的内容就是下图红框中的内容。
在这里插入图片描述
为什么会出现这种情况呢?为什么在bios进入bootloader的时候是0,进入内核值就变了?
我想应该是因此bootmain函数中的循环将各个段加载到了指定位置,其中的详细需要更深层次的理解。

总结

Part2终于写完了!!!!!
后面继续加油。
有问题欢迎各位指出。

  • 18
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值