转载:https://www.cnblogs.com/tolimit/p/4775945.html
操作系统是如何知道代码中的各个段的:
1、(windows下masm汇编工具)直接指明:
dseg segment
data db '1'
dseg ends
cseg segment
assume cs:cseg,ds:dseg,es:dseg
start:
mov ax,dseg
mov ds,ax //将数据段dseg给ds寄存器
mov dl,data;
mov ah,02h
int 21h
mov ah,4ch
int 21h
cseg ends
end start
注:a、代码段寄存器不能由程序员在源程序中对其赋值,其值是由操作系统在装入它进入系统运行时自动赋值的,其它段寄存器都可以。
egg:
使用堆栈段:
mov ax,stack
mov ss,ax
mov sp,stack_top
b、assume伪指令:告诉编译器各个段关联关系,并不生成机器码。
2、linux下编译出的代码段、数据段都是放在代码段中的
3、linux线性地址空间:3G~4G的内核空间,0~3G用户空间,对应物理内存空间:0~1G内核空间,1G~4G用户空间。
4、每个进程都拥有独立的虚拟地址空间,本质上就是每个进程都有单独的页表,页表地址是储存在页表寄存器 CR3 中的,CR3寄存器只有1个,因此不同的进程在执行前,都要在CR3寄存器中为其换上与之配套的页表。从而实现了虚拟地址空间的隔离。 内核线程都是共同使用的一套页表,即内核页表 0x10_0000。(转载:八、用户进程:TSS、用户进程的创建、用户进程的执行(通过调度函数)_tss 是什么用户-CSDN博客)
5、linux下各进程共用用户代码段、用户数据段、内核代码段、内核数据段,地址范围都是0~4G,但不混乱,是因为第3、4点,即线性地址下用户空间在0~3G,每个进程都有单独的页表。当共用一个页表时,各个进程的同一线性地址对应同一页表项,也即对应同一物理内存。
6、所有的tss段都是放在某个数组中的,内核可以该数组首地址赋给tr寄存器
7、操作系统会将未分配的物理内存单独管理(可看做内存池),当需要分配内存时,直接去内存池里去找就可以了,所以不会出现物理地址冲突的问题。