内存分段机制

不羁岁月 提交于 2020-05-08 14:01:53

我们可以写一段简单的c代码(code/memory/segment_1.c):

#include <stdio.h>
int main()
{
   int a = 1;
   printf("Hello, World!");
   return 0;
}

然后将其转为汇编,运行:

gcc -S segment_1.c

之后会生成一个.s 文件(code/memory/segment_1.s),不用细看内容。

我们发现,这个汇编代码中,有 .string main .text,反正分为不同的块。

	.file	"segment_1.c"
	.text
	.section	.rodata
.LC0:
	.string	"Hello, World!"
	.text
	.globl	main
	.type	main, @function
main:
.LFB0:
	.cfi_startproc
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	subq	$16, %rsp
	movl	$1, -4(%rbp)
	leaq	.LC0(%rip), %rdi
	movl	$0, %eax
	call	printf@PLT
	movl	$0, %eax
	leave
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE0:
	.size	main, .-main
	.ident	"GCC: (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0"
	.section	.note.GNU-stack,"",@progbits

进程在内存中,主要是按照这种形式进行存储的。

为什么要分段呢?

我们看上面那张图片,分为不同段,每个段的读写属性是不同的。比如正文段存储代码,就像我们上面的.s文件中的main部分。它在内存中是始终不变的,我们CPU就是从main中去取指执行。所以,它是只读的。

而其他部分,也许是可读可写的。

通过分段,可以对不同的属性代码、数据进行更方便的管理。如果是打乱的放在内存中,那么读写属性就很难控制。

所以通过分段机制,我们可以更好得控制不同段的属性,这有利于内存的组织安排。更多的好处,可以后面慢慢体会。

分段机制与间接寻址

因为现在引入了分段机制,所以如果我们想要访问某个地方的数据,指令,我们会引入间接寻址。

比如说,程序现在运行在代码段(CS),然后呢,他想要访问数据段的某个数据(DS),那么就可以使用 DS的基地址+偏移量,就可以访问到数据段中的数据了。

就像我们下图一样,如果我们运行到某一条指令,他需要 DS:1 的数据,那么我们可以通过数据段开始的地址0x100 加上偏移量1,就可以直接访问到 int a = 1 了。

所以,我们只需要知道不同段的开始地址加上偏移量,就可以访问不同段的内容。

分段机制与LDT表

我们前面说到,因为分段机制,所以,如果我们想要去访问某个段中的内容,我们需要获得每个段的基址。所以,我们需要一个结构去储存每个段的基址。这就是 LDT (本地描述表/local descriptor table) 表。

(名字,有点。。。,至少本地两字说明,这个表是局部的,对于每个进程,都有一个LDT表)。

LDT 表

现在来说说 LDT 表,之前说了分段的好处,那么我们应该怎么设计 LDT 表呢?

我们需要用一些位来表示:可读/可写状态,不同段的基址以及段的长度。

现在,我们可以通过每个进程的 LDT 表找到每个段所在的位置。

GDT 表

那么我们如何找到每个进程的 LDT 表呢?

这个,就轮到 GDT表了,与之前的 LDT 表,就差一个字母。G的意思,就是 global 全局的意思。

那意味着这张表,所有的进程都可以看到,进行访问。

在 GDT 表中,有着不同 LDT 表的地址。这里涉及到 LDTR寄存器,这个寄存器被赋值为 GDT表中的一个 LDT 表的位置,然后CPU 可以通过这个寄存器,找到对应的进程的 LDT表。

可以看下下图。

关于更多的 GDT 和 LDT 的介绍,可以看最后的参考部分。

分段机制与多进程

我们知道,CPU会采用某种策略,运行多个进程。这个时候,我们就需要保证不同的进程的内容,会存在不同的内存中,不能相互干扰。

这就要求,我们之前说的,每个进程都有一个 LDT表。可以将不同的进程内容映射到不同的内存地址。

总结

最后,就拿这张图来总结下吧,大家可以用这张图来回顾下前面的内容。

参考

《深入理解计算机系统》

  • 7.9 加载可执行目标文件

《Linux 内核0.11完全注释》

  • 4.3 分页机制(进阶)

操作系统(哈工大李治军老师)32讲(全)超清 P20 L20 内存使用与分段

GDT(全居描述符表)和LDT(局部描述符表)

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!