ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

linux – 为什么mm_struct-> start_stack和vm_area_struct-> start不指向同一个地址?

2019-06-28 20:41:21  阅读:393  来源: 互联网

标签:linux linux-kernel kernel internals


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

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

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

Vma number 14: Starts at 0x7fff4bb68000, Ends at 0x7fff4bb8a000
Vma number 15: Starts at 0x7fff4bbfc000, Ends at 0x7fff4bbfe000
Vma number 16: Starts at 0x7fff4bbfe000, Ends at 0x7fff4bc00000
Code Segment start = 0x400000, end = 0x400854
Data Segment start = 0x600858, end = 0x600a94
Stack Segment start = 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");

解决方法:

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

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

标签:linux,linux-kernel,kernel,internals
来源: https://codeday.me/bug/20190628/1319030.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有