0%

地址映射与共享

地址映射与共享

实验内容

  • Bochs 调试工具跟踪 Linux 0.11 的地址翻译(地址映射)过程,了解 IA-32Linux 0.11 的内存管理机制;
  • Ubuntu 上编写多进程的生产者-消费者程序,用共享内存做缓冲区;
  • 在信号量实验的基础上,为 Linux 0.11 增加共享内存功能,并将生产者-消费者程序移植到 Linux 0.11

实验步骤

创建test.c

image-20220612154248888

image-20220612154259966

寻找物理地址

首先进入Linux-0.11目录内make编译系统,然后运行系统,编译运行test.c文件

1
2
gcc -o test test.c
./test

image-20220612154459443

此时会进入在test.c内的while死循环,然后ctrl+c暂停bochs。
此时需要让Linux-0.11的test跳出死循环,所以需要找到逻辑地址ds:0X00003004对应的物理地址,将它的内容更改为0。
在终端中输入sreg,得到gdtr的基址值为0x00005cb8,ldtr为0x0068即0000 0000 0110 1000 b,可知索引为1101b即13,TI位为0,即GDT中的第13项为LDT的段描述符。

image-20220612162319691

输入

1
xp /2w 0x00005cb8+13*8

image-20220612162954016

可以得到LDT的基址为0x00fe92d0

ds段选择子为0x0017 => 0000 0000 0001 0111 b,可知索引为10b即2,TI位为1,即LDT中的第2项为ds的段描述符

输入

1
xp/2w 0x00fe92d0+2*8

得到ds段描述符

image-20220612163210299

可以知道ds的基址为0x10000000,所以0x3004对应的线性地址为0x10000000+0x3004=0x10003004

输入

1
xp /w 64*4

获取页目录项

image-20220612164505087

表所在的物理页框号为0x00fa7,即页表在物理内存为0x00fa7000处,从该位置开始查找3号页表项

输入

1
xp /w 0x00fa7000 + 3*4

image-20220612164837721

线性地址0x10003004对应的物理页框号为0x00fa6,和页内偏移0x004接到一起,得到0x00fa6004,这就是变量i的物理地址

1
xp /w 0x00fa6004

验证

image-20220612165035955

修改物理地址,使其变量i为0

1
setpmem 0x00fa6004 4 0

image-20220612165143590

输入c,可以看到,会在bochs中顺利退出

image-20220612165212346

添加系统调用

在unistd.h中增加下面的代码

image-20220612155524270

再添加系统调用

image-20220612155644251

注意:要在挂载下再修改一次

修改sys.h文件

增加函数声明

image-20220612155826510

image-20220612155924786

在system_call.s中把nr_system_calls改为78

image-20220612165738290

增加shm.c

在kernel目录下

image-20220612165927254

然后修改kernel下的Makefile

image-20220612170053415

编写消费者和生产者程序

producer.c

image-20220612203642964

consumer.c

image-20220612203703637

运行验证

编译

1
2
gcc -o pro producer.c
gcc -o con consumer.c

image-20220612202823323

输入

1
2
pro > proOutput &
con > conOutput &

image-20220612202905073

image-20220612203010281

输入

1
sync

关闭linux-0.11回到ubunt终端,输入sudo less hdc/usr/root/conOutput查看结果如下

image-20220612203138227

问题回答

对于地址映射实验部分(第一部分),列出你认为最重要的几步(不超过四步),并给出你获得的实际数据。

1
2
3
4
输入命令u/7反汇编,查看变量i对应的逻辑地址
逻辑地址找虚拟地址要通过段表,也就是IDT表,然后IDT表要根据LDTR寄存器和GDT表,对应的命令就是sreg
根据ds(代码段)寄存器查找IDT表,得到基址,然后通过基址 + 逻辑地址 = 虚拟地址
根据虚拟地址找到物理地址,核心就是查找页表

image-20220612154459443

image-20220612162319691

image-20220612162954016

image-20220612163210299

image-20220612164505087

image-20220612164837721

test.c退出后,如果马上再运行一次程序,并再进行地址跟踪,你会发现哪些异同?为什么?

1
2
再运行一次程序,等同于重来,变量i重新被赋非0值,所以仍然会死循环。
继续进行地址跟踪,根据虚拟地址找到物理地址,发现物理地址和第一次运行时的不一样了,因为在这个进程没有被运行时,内存是会被释放的,所以其他进程是可以利用这个内存的,虽然还是这个虚拟地址,但是重新分配内存的时候,物理地址并不一定还是那个地址。