可执行程序加载到内存的过程

Posted zzfx

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了可执行程序加载到内存的过程相关的知识,希望对你有一定的参考价值。

http://blog.csdn.net/q_l_s/article/details/52594252

在linux中,程序的加载,涉及到两个工具,linker 和loader。Linker主要涉及动态链接库的使用,loader主要涉及软件的加载。

1、  exec执行一个程序

2、  elf为现在非常流行的可执行文件的格式,它为程序运行划分了两个段,一个段是可以执行的代码段,它是只读,可执行;另一个段是数据段,它是可读写,不能执行。

3、  loader会启动,通过mmap系统调用,将代码端和数据段映射到内存中,其实也就是为其分配了虚拟内存,注意这时候,还不占用物理内存;只有程序执行到了相应的地方,内核才会为其分配物理内存。

4、  loader会去查找该程序依赖的链接库,首先看该链接库是否被映射进内存中,如果没有使用mmap,将代码段与数据段映射到内存中,否则只是将其加入进程的地址空间。这样比如glibc等库的内存地址空间是完全一样。

因此一个2M的程序,执行时,并不意味着为其分配了2M的物理内存,这与其运行了的代码量,与其所依赖的动态链接库有关。

运行过程中链接动态链接库与编译过程中链接动态库的区别。

我们调用动态链接库有两种方法:一种是编译的时候,指明所依赖的动态链接库,这样loader可以在程序启动的时候,来所有的动态链接映射到内存中;一种是在运行过程中,通过dlopen和dlfree的方式加载动态链接库,动态将动态链接库加载到内存中。

这两种方式,从编程角度来讲,第一种是最方便的,效率上影响也不大,在内存使用上有些差别。

第一种方式,一个库的代码,只要运行过一次,便会占用物理内存,之后即使再也不使用,也会占用物理内存,直到进程的终止。
第二中方式,库代码占用的内存,可以通过dlfree的方式,释放掉,返回给物理内存。

这个差别主要对于那些寿命很长,但又会偶尔调用各种库的进程有关。如果是这类进程,建议采用第二种方式调用动态链接库。

 

mmap()和vma相关和底层的驱动相关

如果用户的空间映射到虚拟内存大块的映射 用mmap

驱动需要做一个简单的线性的设备内存映射, 到一个用户地址空间, remap_pfn_range 几乎是所有你做这个工作真正需要做的. 下列的代码从 drivers/char/mem.c 中得来, 并且显示了这个任务如何在一个称为 simple ( Simple Implementation Mapping Pages with Little Enthusiasm)的典型模块中进行的.

static int simple_remap_mmap(struct file *filp, struct vm_area_struct *vma) 
{
 if (remap_pfn_range(vma, vma->vm_start, vm->vm_pgoff,
 vma->vm_end - vma->vm_start,
 vma->vm_page_prot))
 return -EAGAIN;
 vma->vm_ops = &simple_remap_vm_ops;
 simple_vma_open(vma);
 return 0; 
} 

如你所见, 重新映射内存只不过是调用 remap_pfn_rage 来创建必要的页表.

以上是关于可执行程序加载到内存的过程的主要内容,如果未能解决你的问题,请参考以下文章

c语言 内存,可执行文件

链接器链接过程及相关概念解析

链接一

PE文件动态加载执行过程

Linux编程中链接库的使用

CPU阿甘之烦恼