就我对内核内存管理Linux理解,每个进程中都有一个负责地址空间的mm_struct结构,一个重要的内存区域是堆栈,这应该通过vm_area_struct内存区域来标识,mm_struct本身有一个指针mm_struct-
我遇到了下面的代码,我无法理解的是为什么任何内存区域的开始/结束地址都不等于mm_struct-
加载编译后的内核模块的一些结果:
Vma编号14:开始于0x7fff4bb68000,结束于0x7fff4bb8a000 Vma编号15:开始于0x7fff4bbfc000,结束于0x7fff4bbfe000 Vma编号16:开始于0x7fff4bbfe000,结束于0x7fff4bc00000代码段开始=0x400000,结束=0x400854数据段开始=0x600858,结束=0x600a94堆栈段开始=0x7fff4bb88420
可以发现堆栈段start(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,我想你会发现它们都有相同的start_stack值。但是只有主线程的堆栈指针会在主堆栈vma中。其他线程将各自拥有自己的堆栈vma——这样每个线程的堆栈就可以独立增长。
一般来说,一个进程有一个mm_struct,但许多vm_area_struct,每个都响应一个映射区域。
例如,在32位系统中,进程的虚拟地址空间为4GB,所有地址空间都由mm_struct指向。但是,4GB空间内可以有许多区域。每个区域都由vm_area_struct指向,并且该区域受到vm_area_struct的限制-
下面是详细介绍。