linux 32位进程虚拟地址空间: 0xFFFFFFFF ------- OS 1GB 0xC0000000 ------- User 3GB Space 0x00000000 ------- 进程创建: 创建独立的虚拟地址空间 读取可执行文件头,并建立空间与可执行文件的映射关系 将CPU的指令寄存器设置成可执行文件入口地址,启动运行 ELF文件链接试图和执行试图: 以代码段为代表的权限是可读可执行的段 以数据段,BSS段为代表的权限是可读可写的段 以只读数据段为代表的只读段 对于相同权限的段,把他们合并到一起当作一个段进行映射."Segment"包含一个或多个属性相类似的"Section" readelf -l sectionmapping 查看多少各Segment Elf file type is EXEC (Executable file) Entry point 0x8048cf8 There are 5 program headers, starting at offset 52 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align LOAD 0x000000 0x08048000 0x08048000 0xa334b 0xa334b R E 0x1000 LOAD 0x0a334c 0x080ec34c 0x080ec34c 0x00cd4 0x023c0 RW 0x1000 NOTE 0x0000d4 0x080480d4 0x080480d4 0x00044 0x00044 R 0x4 TLS 0x0a334c 0x080ec34c 0x080ec34c 0x00010 0x00028 R 0x4 GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4 Section to Segment mapping: Segment Sections... 00 .note.ABI-tag .note.gnu.build-id .rel.plt .init .plt .text __libc_thread_freeres_fn __libc_freeres_fn .fini .rodata __libc_thread_subfreeres __libc_subfreeres __libc_atexit .eh_frame .gcc_except_table 01 .tdata .init_array .fini_array .jcr .data.rel.ro .got .got.plt .data .bss __libc_freeres_ptrs 02 .note.ABI-tag .note.gnu.build-id 03 .tdata .tbss 04 其中NOTE,TLS,GNU_STACK在装载时起辅助作用。 所有相同属性的“Section”被归类到一个“Segment”,并映射到同一个VMA。 程序头表: p_type 类型:LOAD,DYNAMIC,INTERP p_offset 文件中偏移 p_vaddr 在进程虚拟空间的起始位置 p_paddr 物理装载位置 p_filesz “Segment”的大小 p_memsz "Segment"在虚拟地址空间中的长度 p_flags 权限属性, R W X p_align 对齐属性
堆和栈: 可以通过查看/proc来获取进程虚拟地址空间分配 phil~/repos/my_bible $ cat /proc/7841/maps 08048000-080ec000 r-xp 00000000 08:04 8926198 /home/phil/repos/my_bible/sectionmapping 080ec000-080ee000 rw-p 000a3000 08:04 8926198 /home/phil/repos/my_bible/sectionmapping 080ee000-080ef000 rw-p 00000000 00:00 0 0934c000-0936e000 rw-p 00000000 00:00 0 [heap] b7744000-b7745000 r-xp 00000000 00:00 0 [vdso] bf8ea000-bf90b000 rw-p 00000000 00:00 0 [stack] vdso是一个内核的模块,进程可以通过访问这个VMA跟内核通信。 linux映射完第二个Segment之后,把最后一个页面的剩余部分清0,然后调用内核的do_brk(),把.bss和__libcfreeres_ptrs的剩余部分放在堆段上,可看fs/Binfmt_elf.c中的load_elf_interp()和elf_map() 堆的最大申请数量: 受到的影响是操作系统版本,程序本身大小,用到的动态/共享库的数量,大小,程序栈数量,大小等,甚至每次运行的结果不一样,特别是随机地址空间分布的特性被使用后。 进程栈初始化: 系统环境变量和进程的运行参数,操作系统在进程启动前将这些信息提前保存在虚拟空间的栈中。