vm_area_struct与mm_struct中内存区域的关联

vm_area_struct与mm_struct中内存区域的关联

Content #

这个事情是在 load_elf_binary 里面实现的。加载内核的是它,启动第一个用户态进程 init 的是它,fork 完了以后,调用 exec 运行一个二进制程序的也是它。

当 exec 运行一个二进制程序的时候,除了解析 ELF 的格式之外,另外一个重要的事情就是建立内存映射。

static int load_elf_binary(struct linux_binprm *bprm)
{
......
  setup_new_exec(bprm);
......
  retval = setup_arg_pages(bprm, randomize_stack_top(STACK_TOP),
         executable_stack);
......
  error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt,
        elf_prot, elf_flags, total_size);
......
  retval = set_brk(elf_bss, elf_brk, bss_prot);
......
  elf_entry = load_elf_interp(&loc->interp_elf_ex,
              interpreter,
              &interp_map_addr,
              load_bias, interp_elf_phdata);
......
  current->mm->end_code = end_code;
  current->mm->start_code = start_code;
  current->mm->start_data = start_data;
  current->mm->end_data = end_data;
  current->mm->start_stack = bprm->p;
......
}

load_elf_binary 会完成以下的事情:

  1. 调用 setup_new_exec,设置内存映射区 mmap_base;
  2. 调用 setup_arg_pages,设置栈的 vm_area_struct,这里面设置了 mm->arg_start 是指向栈底的,current->mm->start_stack 就是栈底;
  3. elf_map 会将 ELF 文件中的代码部分映射到内存中来;
  4. set_brk 设置了堆的 vm_area_struct,这里面设置了 current->mm->start_brk = current->mm->brk,也即堆里面还是空的;
  5. load_elf_interp 将依赖的 so 映射到内存中的内存映射区域。

最终就形成下面这个内存映射图。

Viewpoints #

From #

22 | 进程空间管理:项目组还可以自行布置会议室