• 关于elf文件load段上内存映射


    (这里都是16进制数字)

    这里ROUNDOWN是向下对齐,那么就是比如1434,1000对齐到1000,434对齐到0

    这里ROUNUP是向上对齐,那么就是比如1434,1000对齐到2000,434对齐到1000

    代码如上,

    假设我们有两个load段,可以发现这俩load的偏移地址(关于可执行文件)是连在一起的,但是虚拟地址查了一个页表大小0x1000,我们过一遍代码

    第一个load

    offset=0

    vaddr=10000+g,(g是一个偏移量,是吧这段load到虚拟内存闲的地方,然后它能被页表大小整除)

    aligned_vaddr = 10000+g

    filesz = 434+ 0;

    memsz=434

    那么mmap之后,就会在10000+g这个位置开始映射,然后距离文件开始位置为0的434字节映射

    第二个load

    offset=434

    vaddr=11434+g,(g是一个偏移量,是吧这段load到虚拟内存闲的地方,然后它能被页表大小整除)

    aligned_vaddr = 11000+g

    filesz = 434+ 77c;

    memsz=7b4+434

    那么mmap之后,就会在11000+g这个位置开始映射,然后把距离文件开始位置为0的434+77c字节映射

     之后第二段还需要上.bss section

    那么mmap之后,就会在11000+g+1000这个位置开始映射,然后把距离文件开始位置为0的remaining_bss字节映射,内容全部映射为0(匿名映射,映射为0)

    那么最后的虚拟内存结构为(我们把g省去)

    12000+remaining_bss-----

               .bss(全为0)

    12000-----------------

    11bb0------------------

                   load2

    11434------------------

                    load1

    11000------------------

    10434------------------

                   load1

    10000 ------------------

    最后发现是和程序头表所展示的虚拟内存是一样的

    我们假设两个超过页表大小的段

                    offset          vaddr         filesz

    load1         0                10000        1434

    load2        1434           12434        1434

    第一个load

    offset=0

    vaddr=10000+g,(g是一个偏移量,是吧这段load到虚拟内存闲的地方,然后它能被页表大小整除)

    aligned_vaddr = 10000+g

    filesz = 1434;

    那么mmap之后,就会在10000+g这个位置开始映射,然后距离文件开始位置为0的1434字节映射

    第二个load

    offset=1434

    vaddr=12434+g,(g是一个偏移量,是吧这段load到虚拟内存闲的地方,然后它能被页表大小整除)

    aligned_vaddr = 12000+g

    filesz = 434+ 1434;

    那么mmap之后,就会在12000+g这个位置开始映射,然后把距离文件开始位置为1000的434+1434字节映射

    那么最后的虚拟内存结构为(我们把g省去)

    12000+434+1434------------------

                   load2

    12434------------------

                   一部分load1

    12000------------------

    11434------------------

                   load1

    10000 ------------------

    最后发现是和程序头表所展示的虚拟内存是一样的

    所以具体来说,就是关于offset,这部分就是之前段的总和

    比如段a,b,c

    a就是0

    b就是size.a

    c就是size.a+size.b

    假设现在有俩段,大小分别是x和y

    那么编译出来以后他们的虚拟地址会排布如下

    x:10000

    y:x.size%1000+10000+1000

    也就是说,如果一个段多用了一个页表,下个段就把多出来的这部分记住,并且再开一个页表

    这样当前一个段映射完以后,我们其实映射肯定是下一个页表(这时候y会被round)

    那么多出来的这部分就是x.size%1000,那么就重新设置偏移位置

    那么这个操作会往回走x.size%1000,因为y的offset就是包含了之前的所有的load大小

    那么我们我们会发现,y round之后是11000,那么,偏移就是x.size%1000,也就是offset往回走,我们load y的时候多load了x某部分,这部分大小是x.size%1000,然后我们load大小也加了这个大小,最后结果就是再地址11000,load了大小为x.size%1000+y.size的文件

    这样在虚拟地址上,我们load到正好是x.size%1000+10000+1000的位置开始是这个段,然后对齐页表的位置填充了一部分大小为x.size%1000的x段内容。

  • 相关阅读:
    设计模式之代理模式
    聊聊logback的LevelFilter
    探索Lighthouse性能分数计算背后的奥秘
    基于JAVA+SpringBoot的新闻发布平台
    阿里SQL又爆神作数据生态:MySQL复制技术与生产实践笔记
    考研数据结构与算法(八)查找
    [spring] spring core - 配置注入及其他内容补充
    2023年五一杯数学建模A题无人机定点投放问题求解全过程论文及程序
    RocketMq(三)springBoot集成rocketMq
    数据结构<1>时空复杂度详解
  • 原文地址:https://blog.csdn.net/Kongxiangyunltj/article/details/136655747