【问题标题】:Why mm_struct->start_stack and vm_area_struct->start don't point to the same address?为什么 mm_struct->start_stack 和 vm_area_struct->start 不指向同一个地址?
【发布时间】:2015-01-02 23:09:43
【问题描述】:

据我了解Linux内核中的内存管理,每个进程中都有一个mm_struct结构负责地址空间。一个重要的内存区域是堆栈。这应该由 vm_area_struct 内存区域标识,并且 mm_struct 本身有一个指针 mm_struct->stack_start ,它是堆栈的地址。

我遇到了下面的代码,我无法理解为什么任何内存区域的开始/结束地址都不等于 mm_struct->stack_start 值。任何有助于理解这一点的帮助将不胜感激。谢谢

加载编译内核模块的一些结果:

Vma 编号 14:从 0x7fff4bb68000 开始,在 0x7fff4bb8a000 结束 Vma 编号 15:从 0x7fff4bbfc000 开始,在 0x7fff4bbfe000 结束 Vma 编号 16:从 0x7fff4bbfe000 开始,在 0x7fff4bc00000 结束 代码段开始 = 0x400000,结束 = 0x400854 数据段开始 = 0x600858,结束 = 0x600a94 堆栈段开始 = 0x7fff4bb88420

可以发现栈段起始(0x7fff4bb88420)属于vma编号14,但我不知道地址不同。

内核模块源码:

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/mm.h>

static int pid_mem = 1;

static void print_mem(struct task_struct *task)
{
        struct mm_struct *mm;
        struct vm_area_struct *vma;
        int count = 0;
        mm = task->mm;
        printk("\nThis mm_struct has %d vmas.\n", mm->map_count);
        for (vma = mm->mmap ; vma ; vma = vma->vm_next) {
                printk ("\nVma number %d: \n", ++count);
                printk("  Starts at 0x%lx, Ends at 0x%lx\n",
                          vma->vm_start, vma->vm_end);
        }
        printk("\nCode  Segment start = 0x%lx, end = 0x%lx \n"
                 "Data  Segment start = 0x%lx, end = 0x%lx\n"
                 "Stack Segment start = 0x%lx\n",
                 mm->start_code, mm->end_code,
                 mm->start_data, mm->end_data,
                 mm->start_stack);
}

static int mm_exp_load(void){
        struct task_struct *task;
        printk("\nGot the process id to look up as %d.\n", pid_mem);
        for_each_process(task) {
                if ( task->pid == pid_mem) {
                        printk("%s[%d]\n", task->comm, task->pid);
                        print_mem(task);
                }
        }
        return 0;
}

static void mm_exp_unload(void)
{
        printk("\nPrint segment information module exiting.\n");
}

module_init(mm_exp_load);
module_exit(mm_exp_unload);
module_param(pid_mem, int, 0);

MODULE_AUTHOR ("Krishnakumar. R, rkrishnakumar@gmail.com");
MODULE_DESCRIPTION ("Print segment information");
MODULE_LICENSE("GPL");

【问题讨论】:

    标签: linux linux-kernel kernel internals


    【解决方案1】:

    看起来 start_stack 是 initial 堆栈指针地址。它是在程序执行时由内核根据可执行文件中给出的堆栈段地址计算出来的。我认为它此后根本不会更新。系统至少在一个实例中使用 start_stack:识别哪个 vma 代表“堆栈”(当提供 /proc//maps 时),因为包含该地址的 vma 保证包含(主)堆栈。

    但请注意,这只是“主”(初始)线程的堆栈;多线程程序也会有其他堆栈——每个线程一个。由于它们都共享相同的地址空间,所有线程将显示相同的 vmas 集,我想您会发现它们也都具有相同的 start_stack 值。但是只有主线程的堆栈指针会在主堆栈 vma 中。其他线程将各自拥有自己的堆栈 vmas——这样每个线程的堆栈就可以独立增长。

    【讨论】:

      【解决方案2】:

      一般来说,一个进程有一个mm_struct,但有很多vm_area_struct,每个响应一个映射区域。

      例如,在一个32位系统中,一个进程有一个4GB的虚拟地址空间,所有这些都是由mm_struct所指向的。但是,4GB 空间内可以有许多区域。每个区域都由一个 vm_area_struct 指向,并且该区域由 vm_area_struct->start 和 vm_area_struct->end 限制。因此,显然 mm_struct 结构包含 vm_area_struct 的列表。

      Here是详细介绍。

      【讨论】:

        猜你喜欢
        • 2019-07-15
        • 1970-01-01
        • 2011-05-15
        • 2014-04-05
        • 2021-06-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多