zoukankan      html  css  js  c++  java
  • Chap-6 6.4 进程虚拟地址空间分布

    6.4 进程虚拟空间分布
    6.4.1 ELF文件的链接视图和执行视图
    可执行文件被映射时,是以系统页的长度为单位的,每个段在被映射时的长度应该为系统页长度的
    整数倍。如果不是,那么多余部分也将占用一个页。一个ELF可执行文件往往有十几个段,那么内存
    空间的浪费是可想而知的,有没有办法来减少这种浪费?
    一个简单的方案就是:对于有相同权限的段,把它们合到一起当作一个段进行映射。比如有两个段分别
    叫做“.text”和“.init”,它们包含的分别是程序的可执行代码和初始化代码,权限相同,都是可读并且
    可执行。假设.text段为4097字节,.init为513字节,这两个段分别映射的话就要占用三个页面,但是,
    如果将他们合并成一起映射的话,只需要两个页面,这里页面的大小为4096字节。

    ELF可执行文件引入了一个概念叫做“segment”,一个“segment”包含一个或者多个属性类似的"section"。
    正如上面的例子,如果将“.text”和“.init”一起映射,也就是说映射以后在进程的虚拟空间中只有一个
    相对应的VMA,而不是两个,这样做的好处是可以很明显的减少页内部碎片,节省内存空间。

    自我问题:这里VMA和页的关系?

    “segment”的概念实际上是从装载的角度重新划分了ELF的各个段,在将目标文件链接成可执行文件的时候,
    链接器会尽量把相同属性权限的段分配在同一空间。在ELF中把这些属性相似的,又连在一起的段叫做一个
    “segment”,而系统这是按照“segment”而不是“section”来映射可执行文件的。

    下面是一个在C语言教科书中会出现的Hello World程序:
    //hello.c
    #include <stdio.h>

    int main(int argc, char* argv[]) {

    printf("Hello World! ");
    return 0;
    }

    使用readelf -S hello可知,该可执行文件中共有31个段(section)。也可是使用readelf -l hello来查看
    ELF的“segment”。正如描述“section”属性的结构叫做段表,描述“segment”的结构叫做程序头(Program Header),
    “segment”描述了可执行文件该如何被操作系统映射到进程的虚拟空间,下面是readelf -l hello的输出:


    ***图6.4.1***
    从图中我们可以看出,可执行文件一共有6个segment,从装载的角度看,我们只关心两个“load”类型的
    segment,因为只有该类行的segment才是需要被映射的,其他的segment都是在装载时起辅助作用的。
    图中下半部分描述了section到segment的映射,把具有相同权限属性的section合并到同一个segment中。
    所以总的来说,segment和section是从不同角度来划分同一个ELF可执行文件,这个在ELF中被称为不同的
    视图(View),从secetion角度来看就是链接视图(Linking View),从segment角度来看就是执行视图(Execution View)。

    ELF可执行文件中有一个专门的数据结构叫做程序头表(Program Header Table),用来保存segment的信息。
    因为ELF目标(.o文件)不需要被装载,因此没有程序头表;而ELF可执行文件和共享库文件都有。跟段表一样,
    程序头表也是一个结构体数组,描述如下:
    typedef struct {
    Elf32_Word p_type;
    Elf32_Off p_offset;
    Elf32_Addr p_vaddr;
    Elf32_Word p_paddr;
    Elf32_Word p_filesz;
    Elf32_Word p_memsz;
    Elf32_Word p_flags;
    Elf32_Word p_align;
    }Elf32_Phdr;

    p_type: segment的类型,基本上我们只关注“LOAD”类型的segment。
    p_offset: segment在文件中的偏移。
    p_vaddr: segment的第一个字节在进程虚拟地址空间的起始位置,整个程序头表中,所有LOAD类型元素按照p_vaddr
    从小到大排列。
    p_paddr: segment的物理装载地址。
    p_filesz: segment在ELF文件中所占空间的长度。
    p_flags: segment的权限属性。比如可读“R”,可写“W”, 可执行“X”。
    p_align: segment的对齐属性,实际对齐字节等于2的p_align次方,比如p_align等于10,那么实际的对齐属性就是
    2的10次方,即1024字节。
    对于LOAD类型的段来说,p_memsz的值不能小于p_filesz的值,否则就是不合常理,但是,如果p_memsz的值大于
    p_filesz的值呢?就表示该segment在内存中所分配的空间大小超过文件中实际大小,这部分多余的空间填充为0.
    座位BSS section部分。数据段和BSS段的区别:数据段在程序中初始化,而BSS段的内容全部初始化为0.

  • 相关阅读:
    二维凸包
    luogu_P1287 盒子与球
    luogu_P1993 小K的农场
    luogu_P1712 [NOI2016]区间
    luogu_P2444 [POI2000]病毒
    luogu_P2154 [SDOI2009]虔诚的墓主人
    20191005-T3-U91353 放射性
    编译原理 笔记2 词法分析
    DFA到等价正则表达式的转化
    软件分析笔记10 Soundiness
  • 原文地址:https://www.cnblogs.com/miaoyong/p/3514596.html
Copyright © 2011-2022 走看看