专栏首页原创分享理解进程的新建和执行过程

理解进程的新建和执行过程

本文以linux0.11版本为基础,分析进程的内存布局,现代版本已经发生比较大的变化,都是很多原理都是类似的。 系统维护了一个全局的数据结构叫GDT( Global Descriptor Table),他保存了所有进程的代码段数据段的一些信息。系统有专门的寄存器保存了GDT的地址,叫GDTR。GTDR的格式如下。

在这里插入图片描述

有专门的指令把这个地址加载到GDTR中。叫LGDT。每个进程可以定义一个LDT,用于存储代码段和数据段信息。GDT布局如下。

在这里插入图片描述

GDT每个项(GDT描述符)对应的结构体是

GDT描述符

我们回顾task_struct结构,看到有两个属性desc_struct,和tss_struct。desc_struct是保存进程代码段和数据段信息的,tss_struct是保存进程执行上下文的。这两个结构体的定义如下。

struct desc_struct {
    unsigned long a,b;
}

struct tss_struct {
    long    back_link;  /* 16 high bits zero */
    long    esp0;
    long    ss0;        /* 16 high bits zero */
    long    esp1;
    long    ss1;        /* 16 high bits zero */
    long    esp2;
    long    ss2;        /* 16 high bits zero */
    long    cr3;
    long    eip;
    long    eflags;
    long    eax,ecx,edx,ebx;
    long    esp;
    long    ebp;
    long    esi;
    long    edi;
    long    es;     /* 16 high bits zero */
    long    cs;     /* 16 high bits zero */
    long    ss;     /* 16 high bits zero */
    long    ds;     /* 16 high bits zero */
    long    fs;     /* 16 high bits zero */
    long    gs;     /* 16 high bits zero */
    long    ldt;        /* 16 high bits zero */
    long    trace_bitmap;   /* bits: trace 0, bitmap 16-31 */
    struct i387_struct i387;
};

我们从fork函数开始,看看这些数据结构的设置和关系。我们先来看一下一些宏定义。他是根据进程号(进程id)计算出在GDT中的索引。可参考上图。

/*
 * Entry into gdt where to find first TSS. 0-nul, 1-cs, 2-ds, 3-syscall
 * 4-TSS0, 5-LDT0, 6-TSS1 etc ...
 */
#define FIRST_TSS_ENTRY 4
#define FIRST_LDT_ENTRY (FIRST_TSS_ENTRY+1)
// 第一个tss选择子的偏移是4<<3,4乘以8,等于32,即从GDT的偏移为32开始算,第一个进程的n是0,tss是32
#define _TSS(n) ((((unsigned long) n)<<4)+(FIRST_TSS_ENTRY<<3))
// 第一个ldt选择子的偏移是5<<3,5乘以8,等于40,即从GDT的偏移为40开始算,第一个进程的n是0,ldt是40
#define _LDT(n) ((((unsigned long) n)<<4)+(FIRST_LDT_ENTRY<<3))

下面代码来自fork。

// nr是进程id,计算进程的ldt结构在gdt中的索引,执行该进程的时候,从GDT的第tss->ldt项中取得进程的信息。p即task_struct
p->tss.ldt = _LDT(nr); 
// 设置进程的线性地址的首地址,每个进程占64MB,0.11的进程线性地址是每个进程64M,不是4GB
new_data_base = new_code_base = nr * 0x4000000;
p->start_code = new_code_base;
// 设置线性地址到ldt的描述符中
set_base(p->ldt[1],new_code_base);
set_base(p->ldt[2],new_data_base);
// 把父进程的页目录项和页表复制到子进程,old_data_base,new_data_base是线性地址,父子进程共享物理页面,即copy on write
copy_page_tables(old_data_base,new_data_base,data_limit);
/*
    挂载tss和ldt地址到gdt,nr << 1即乘以2,这里算出的是第nr个进程距离第一个tss描述符地址的偏移,
    单位是8个字节,即选择描述符大小,_LDT是偏移的大小,单位是1,这里是8
*/
set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss));
set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&(p->ldt));
在这里插入图片描述

fork执行完之后,新新建的相关数据结构已经建立好了,并且也和系统的管理数据产生了关联。有自己独立的页表,和父进程共享物理地址。那么当这个进程被调度的时候,他会发生什么。 执行进程的时候,根据进程号,算出tss在gdt的索引,然后把索引里指向的tss里的上下文也加载到对应的寄存器,tss信息中的ldt索引首先从gdt找到进程ldt结构体数据的首地址,即desc_struct结构体数组,然后根据当前段的属性,比如代码段,则从cs中取得选择子,系统从ldt表中取得进程线性空间的首地址、限长、权限等信息。用线性地址的首地址加上ip中的偏移,得到线性地址,然后再通过页目录和页表得到物理地址,物理地址还没有分配则进行缺页异常等处理。

本文分享自微信公众号 - 编程杂技(theanarkh),作者:theanarkh

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-03-02

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 通过linux0.11理解僵尸进程

    首先僵尸进程产生的原因是子进程退出了,但是父进程没有回收他的资源(pcb),所以我们从源头开始分析这个过程。那就是子进程退出的时候。进程是通过exit系统调用退...

    theanarkh
  • 如何在nodejs中实现兄弟进程通信

    在nodejs主进程中,开启一个额外的子进程A,进程A负责和线程池通信,完成cpu密集型的任务。通过nodejs主进程创建出来的多个nodejs工作进程可以把任...

    theanarkh
  • 进程的执行和挂起

    进程是对逻辑的抽象,我们从操作系统的书籍中对进程有了很多的认识,但是对进程的实现可能不太了解,这篇文章尝试解释一下关于进程实现的大致原理。 进程的实现,...

    theanarkh
  • ps 命令详解

    java404
  • 通过linux0.11理解僵尸进程

    首先僵尸进程产生的原因是子进程退出了,但是父进程没有回收他的资源(pcb),所以我们从源头开始分析这个过程。那就是子进程退出的时候。进程是通过exit系统调用退...

    theanarkh
  • linux网络编程之进程间通信基础(一):进程间通信概述

    一、顺序程序与并发程序特征 顺序程序特征 顺序性 封闭性:(运行环境的封闭性) 确定性 可再现性 并发程序特征 共享性 并发性 随机性 二、进程互斥 ...

    s1mba
  • 【专业技术第一讲】进程的一生

    学习编程,进程跳不过去,好多初学者可以向背教科书一样说出进程和线程的区别,但是很少能真正的理解进程整个运行过程。搞清楚进程的运行机制,进程运行的各个阶段也并不是...

    程序员互动联盟
  • 多进程的组织、交替、合作

    上文中(操作系统之进程管理(1):从CPU如何执行进程说起),我们说过操作系统为每个程序提供了一个叫做PCB(Process Control Block进程控制...

    xujjj
  • 众筹项目能否成功?用机器学习预测可以早知道

    安妮 编译自 Shrikar Archak 量子位出品 | 公众号 QbitAI Kickstarter是一家美国的众筹平台。自2009年成立至今,已经有36万...

    量子位
  • linux进程管理:进程,程序,线程 & 9个进程管理工具 & 作业控制

    程序 ------》系统调用-------》缓存(内存) -------》cpu处理 执行任务

    用户5807183

扫码关注云+社区

领取腾讯云代金券