第 6 章 进程装载

目录

6.1. 进程
6.2. Linunx内核装载ELF过程

6.1. 进程

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()

堆的最大申请数量:
受到的影响是操作系统版本,程序本身大小,用到的动态/共享库的数量,大小,程序栈数量,大小等,甚至每次运行的结果不一样,特别是随机地址空间分布的特性被使用后。

进程栈初始化:
系统环境变量和进程的运行参数,操作系统在进程启动前将这些信息提前保存在虚拟空间的栈中。