背景知识

你需要了解 虚拟空间的构成

而堆区的末尾(上面左方标记的 brk ),称为程序中断处(program break)。严格来说堆区是我们以程序的视角来看的,而以内存的视角来看,堆区、bss、data、rodata 均属于 data segment。

man 的 section 数字

  • 1 - commands
  • 2 - system calls
  • 3 - library calls
  • 4 - special files
  • 5 - file formats and convertions
  • 6 - games for linux
  • 7 - macro packages and conventions
  • 8 - system management commands
  • 9 - others

sbrk 和 brk

brk 系列系统调用可以改变 data segment 的大小,也即可以改变堆内存的结束位置。

  • brk: 设置 break 位置为给定的位置。
    • 返回值:
      • 如果成功,返回 0
      • 如果失败,返回 -1,且 errno 被设置为 ENOMEM
  • sbrk: 将 break 位置增加给定字节数。
    • 返回值:
      • 如果成功,返回上一次 brk 的位置(可以调用 sbrk (0) 获取当前 brk 位置)
      • 如果失败,返回 -1,且 errno 被设置为 ENOMEM
       #include <unistd.h>

       int brk(void *addr);
       void *sbrk(intptr_t increment);

mmap 和 munmap

mmap 的作用是将文件映射到进程的地址空间中,而 munmap 则是将映射的内存释放。

  • addr: 创建映射的参考位置(若 NULL,则自动选取)(仅供参考,实际的位置可能高于它)
  • length: 映射的长度
  • prot: 保护等级
    • PROT_NONE: 不可访问
    • PROT_READ: 可读
    • PROT_WRITE: 可写
    • PROT_EXEC: 可执行
  • flags: 映射方式
    • AP_SHARED: 共享映射,即允许其他进程访问
    • AP_SHARED_VALIDATE: 共享映射,并且确保其它 flags 都是有效的
    • AP_PRIVATE: 私有 COW 映射,即不允许其他进程访问
    • AP_ANONYMOUS: 匿名映射,即不创建文件映射,默认填充 0
    • AP_FIXED: 映射的位置固定,即不允许自动选取位置,强制使用给定 addr
    • AP_GROWSDOWN: 不要使用这个 Flag
    • AP_DENYWRITE: 不允许写入,即不允许其他进程写入映射区域
    • AP_FIXED_NOREPLACE: 同 MAP_FIXED,但不允许破坏已经存在的映射范围
    • AP_HUGETLB: 使用 Huge TLB 映射,即允许单个页面非常大
    • MAP_SYNC: 配合 MAP_SHARED_VALIDATE 使用,同步写入,即写入时将数据同步到磁盘
    • MAP_UNINITIALIZED: 创建一个未初始化的映射,即不初始化数据,能够提高一些性能
       #include <sys/mman.h>
       void *mmap(void *addr, size_t length, int prot, int flags,
                  int fd, off_t offset);
       int munmap(void *addr, size_t length);

mprotect

mprotect 的作用是修改映射区域的保护等级,即修改映射区域的访问权限。

prot flags:

  • PROT_NONE 不可访问
  • PROT_READ 可读
  • PROT_WRITE 可写
  • PROT_EXEC 可执行
  • PROT_SEM 别用
  • PROT_SAO 别用
  • PROT_GROWSUP 应用此保护直至映射区域的顶部
  • PROT_GROWSDOWN 应用此保护直至映射区域的底部(用于常规的栈设计,向下增长)
       #include <sys/mman.h>

       int mprotect(void *addr, size_t len, int prot);