为什么mm_struct-> start_stack和vm_area_struct->开始没有指向同一个地址?

时间:2015-01-02 23:09:44

标签: linux linux-kernel kernel internals

据我了解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");

2 个答案:

答案 0 :(得分:2)

看起来start_stack是初始堆栈指针地址。它是在程序执行时由内核计算的,并且基于可执行文件中给出的堆栈部分地址。我以后根本不认为它会得到更新。系统在至少一个实例中使用start_stack:识别哪个vma代表&#34;堆栈&#34; (当提供/ proc // maps时),因为包含该地址的vma保证包含(主)栈。

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

答案 1 :(得分:1)

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

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

Here是详细介绍。