Lab5用户进程管理内存布局解析

目录

一、解读Lab5的kernel.ld文件

1.获取bin/kernel的symbols table

​2.excel表格数据整理

3.将kernel_symbol_table_1按照B列排序

4.kernel.ld文件内容

5.SECTIONS->. = 0xC0100000;解读

6.ENTRY(kern_entry)解读

7.SECTIONS->.text解读

8.SECTIONS->PROVIDE(etext = .);解读

9.SECTIONS->.rodata解读

10.SECTIONS->.stab解读

11.SECTIONS->.data解读

12.SECTIONS->.data.pgdir解读

13.SECTIONS->.bss解读

二、总结


对于用户进程的内存布局,是由编译和连接过程决定。我认为编译和链接会确定可执行文件的虚拟内存布局,这种结论可以通过解读可执行文件的符号表证实。

一、解读Lab5的kernel.ld文件

为了解读kernel.ld文件,需要通过这个文件编译出可执行文件bin/kernel,然后需要获得kernel symbols table,最后解读kernel symbols table中的地址字段,就能够理解清楚bin/kernel的内存布局。

1.获取bin/kernel的symbols table

通过命令readelf -s bin/kernel获取kernel的symbols table


2.excel表格数据整理

将步骤1的kernel的symbols table拷贝到excell表格中,获得原始的数据kernel_symbol_table_1。

3.将kernel_symbol_table_1按照B列排序

排序后的kernel_symbol_table_2,他的虚拟内存地址从小到大排列。

4.kernel.ld文件内容

/* Simple linker script for the ucore kernel.
   See the GNU ld 'info' manual ("info ld") to learn the syntax. */

OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(kern_entry)

SECTIONS {
    /* Load the kernel at this address: "." means the current address */
    . = 0xC0100000;

    .text : {
        *(.text .stub .text.* .gnu.linkonce.t.*)
    }

    PROVIDE(etext = .); /* Define the 'etext' symbol to this value */

    .rodata : {
        *(.rodata .rodata.* .gnu.linkonce.r.*)
    }

    /* Include debugging information in kernel memory */
    .stab : {
        PROVIDE(__STAB_BEGIN__ = .);
        *(.stab);
        PROVIDE(__STAB_END__ = .);
        BYTE(0)     /* Force the linker to allocate space
                   for this section */
    }

    .stabstr : {
        PROVIDE(__STABSTR_BEGIN__ = .);
        *(.stabstr);
        PROVIDE(__STABSTR_END__ = .);
        BYTE(0)     /* Force the linker to allocate space
                   for this section */
    }

    /* Adjust the address for the data segment to the next page */
    . = ALIGN(0x1000);

    /* The data segment */
    .data : {
        *(.data)
    }

    . = ALIGN(0x1000);
    .data.pgdir : {
        *(.data.pgdir)
    }

    PROVIDE(edata = .);

    .bss : {
        *(.bss)
    }

    PROVIDE(end = .);

    /DISCARD/ : {
        *(.eh_frame .note.GNU-stack)
    }
}

5.SECTIONS->. = 0xC0100000;解读

1)在Lab5的实验环境中,编译获取编译过程输出

2)链接器将bin/kernel和obj/__user_XXX.out应用程序链接在一起

+ ld bin/kernel

ld -m    elf_i386 -nostdlib -T tools/kernel.ld -o bin/kernel  obj/kern/init/entry.o obj/kern/init/init.o obj/kern/libs/stdio.o obj/kern/libs/readline.o obj/kern/debug/panic.o obj/kern/debug/kdebug.o obj/kern/debug/kmonitor.o obj/kern/driver/ide.o obj/kern/driver/clock.o obj/kern/driver/console.o obj/kern/driver/picirq.o obj/kern/driver/intr.o obj/kern/trap/trap.o obj/kern/trap/vectors.o obj/kern/trap/trapentry.o obj/kern/mm/pmm.o obj/kern/mm/swap_fifo.o obj/kern/mm/vmm.o obj/kern/mm/kmalloc.o obj/kern/mm/swap.o obj/kern/mm/default_pmm.o obj/kern/fs/swapfs.o obj/kern/process/switch.o obj/kern/process/entry.o obj/kern/process/proc.o obj/kern/schedule/sched.o obj/kern/syscall/syscall.o  obj/libs/string.o obj/libs/printfmt.o obj/libs/hash.o obj/libs/rand.o -b binary  obj/__user_hello.out obj/__user_badarg.out obj/__user_forktree.out obj/__user_badsegment.out obj/__user_faultread.out obj/__user_pgdir.out obj/__user_exit.out obj/__user_softint.out obj/__user_waitkill.out obj/__user_spin.out obj/__user_yield.out obj/__user_divzero.out obj/__user_testbss.out obj/__user_faultreadkernel.out obj/__user_forktest.out

由于obj/kern/init/entry.o是第一个链接的文件,所以他的地址使用起始地址0xC0100000,不难发现symbol table中的地址顺序是依靠实际链接目标文件顺序

6.ENTRY(kern_entry)解读

bin/kernel的入口地址是kern_entry,加载器从该地址开始加载并执行程序。

7.SECTIONS->.text解读

该段存放的是代码段,代码段表示执行程序集合,具体在符号表中的体现就是函数地址。

8.SECTIONS->PROVIDE(etext = .);解读

该部分表示在symbols table中生成一个etext字段。

9.SECTIONS->.rodata解读

.rodata表示read only data segment,下图可以看出在bin/kernel中存在若干个只读数据在rodata数据段中。

其中default_pmm_manager是rodata,主要是用const修饰的全局变量

10.SECTIONS->.stab解读

bin/kernel的调试信息存在在stab段中

该段内存虚拟地址如下:

11.SECTIONS->.data解读

.data是数据段,bin/kernel的数据段如下

其中,bootstack是数据段,在汇编语言中进行定义

其中,shiftmap是数据段,在c语言中进行定义,shiftmap变量是全局变量,并且已经初始化了。

其中,idt_pd是数据段,在c语言中进行定义,idt_pd变量是全局变量,并且已经初始化了。

总结来看,.data表示已经初始化,非零值的数据段

12.SECTIONS->.data.pgdir解读

.data.pgdir代表数据段中的页表段,该段单独存在,表示页表的存在范围。在entry.S汇编代码中,对页表段进行了创建赋值。

在symbol table中,表示有两个函数处理页表

13.SECTIONS->.bss解读

.bss是数据段,bin/kernel的数据段如下

其中buf是bss中的成员,它位于readline.c函数中。

其中is_panic是bss中的成员,位于panic.c函数中

其中swap_out_num是bss中的成员,位于swap.c函数中

.bss段存放的是未初始化的全局变量,但是当全局数据初始化为0的时候,也将该变量放在.bss中处理。

二、总结

关于用户进行内存布局,最重要的是代码段、数据段、调试段的符号地址。这些地址在链接器的控制下,给定symbols table。其中ENTRY(kern_entry)规定加载器的加载地址,其中. = 0xC0100000;规定bin/kernel的内存布局起始地址,其中symbol table中的地址顺序是依靠实际链接目标文件顺序。

在bin/kernel中有三类数据段,分别是.rodata、.data、.bss。最让人分不清的是.data和.bss的区别。在这里,.data表示已经初始化的全局变量区域(非0初始化),而.bss表示未初始化化的全局变量区域(包括初始化为0)。对于大多数的操作系统,在程序加载的时候会把bss全局变量清零,无需动手清零,但是动手清零是个好的编程习惯。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值