用户态与内核态划分

89723dc967b59f6f49419082f6ab7659.webp

用户态布局

  1. unsigned long mmap_base; /* base of mmap area */
  2. unsigned long total_vm; /* Total pages mapped */
  3. unsigned long locked_vm; /* Pages that have PG_mlocked set */
  4. unsigned long pinned_vm; /* Refcount permanently increased */
  5. unsigned long data_vm; /* VM_WRITE & ~VM_SHARED & ~VM_STACK */
  6. unsigned long exec_vm; /* VM_EXEC & ~VM_WRITE & ~VM_STACK */
  7. unsigned long stack_vm; /* VM_STACK */
  8. unsigned long start_code, end_code, start_data, end_data;
  9. unsigned long start_brk, brk, start_stack;
  10. unsigned long arg_start, arg_end, env_start, env_end;

total_vm 数据页的数目
locked_vm 锁定不能换出
pinned_vm 不能换出也不能移动
data_vm 存放数据的页的数目
exec_vm 存放可执行文件的页的数目
stack_vm 栈所占的页的数目
stac_brk 堆的起始位置,brk 结束位置,malloc 通过改变 brk 申请内存
arg_start/end 参数列表的位置,env_start/end 环境变量位置,均在栈中最高地址地方
mmap_base 标识虚拟地址中用于内存映射的起始地址
空间从高地址像低地址增长
通过映射一块区域到物理内存,辅助实现 malloc 申请大内存块
映射一块区域到 so 文件,辅助加载动态链接库 so 文件
f83b8d49b4e74c0e255b5735044c1eb1.webp

struct vm_area_struct *mmap;    /* list of VMAs */
struct rb_root mm_rb;

单链表:串联区域,将所有内存映射空间联系在一起
红黑树:快速查找内存区域,辅助实现快速修改

struct vm_area_struct {
  /* The first cache line has the info for VMA tree walking. */
  unsigned long vm_start;    /* Our start address within vm_mm. */
  unsigned long vm_end;    /* The first byte after our end address within vm_mm. */
  /* linked list of VM areas per task, sorted by address */
  struct vm_area_struct *vm_next, *vm_prev;
  struct rb_node vm_rb;
  struct mm_struct *vm_mm;  /* The address space we belong to. */
  struct list_head anon_vma_chain; /* Serialized by mmap_sem &
            * page_table_lock */
  struct anon_vma *anon_vma;  /* Serialized by page_table_lock */
  /* Function pointers to deal with this struct. */
  const struct vm_operations_struct *vm_ops;
  struct file * vm_file;    /* File we map to (can be NULL). */
  void * vm_private_data;    /* was vm_pte (shared mem) */
} __randomize_layout;

vm_rb 将此区域放到红黑树上
vm_ops 对内存区域可做的操作定义
anon_vma 映射到物理内存也叫匿名映射
vm_file 映射到文件时指定被映射的文件

通过 load_elf_binary 将 vm_area_struct 和内存区域关联起来。(起作用还有启动第一个进程时被 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;
......
}

setup_new_exec 设置内存映射区 mmap_base
setup_arg_pages 设置栈的 vm_area_stuct
设置 mm->arg_start 执行栈底
设置 current->mm->start_stack
elf_map 将 ELF 文件中的代码部分映射到内存
set_brk 设置堆的 vm_area_struct
current->mm->start_brk = current->mm->brk,空堆
load_elf_interp 将依赖的 so 映射到内存中的映射区域a3881e90-42ea-4e35-a067-1b645f3ad4d0.webp
修改映射的情况
函数调用,改变栈顶指针
通过 malloc 申请堆内存空间
小内存分配 brk 改变堆结束位置
大内存分配 malloc 执行 mmap