2009-07-30 188 views
35

我想在这里收集在Windows,Linux和OSX上运行可执行文件时会发生什么情况。特别是,我想正确理解操作的顺序:我的猜测是可执行文件格式(PE,ELF或Mach-O)由内核加载(但我忽略了可执行文件的各个部分(可执行文件和Linkable Format)和它们的含义),然后你有动态链接器来解析引用,然后运行__init部分可执行文件,然后执行main,然后执行__fini,然后程序完成,但是我确定它是非常粗糙,可能是错误的。当你运行一个程序时会发生什么?

编辑:现在的问题是CW。我正在填补Linux。如果有人想为Win和OSX做同样的事情,那就太好了。

+1

这仅仅是我,还是这个问题的范围太广泛了? – mezoid 2009-07-30 02:20:21

+0

我不认为它太宽泛,但应该是社区wiki – 2009-07-30 02:23:13

+0

如果我没有得到足够的反馈意见,我想对它进行奖励。如果它是CW,我将无法做到。 – 2009-07-30 02:32:40

回答

0

那么,根据您的确切定义,您必须考虑用于.Net和Java等语言的JIT编译器。当你运行一个.Net“exe”,这在技术上不是“可执行的”时,JIT编译器就介入并编译它。

1

只要图像加载到内存中,魔术就会接管。

30

这当然是在一个非常高的和抽象的水平!

Executable - No Shared Libary: 

Client request to run application 
    ->Shell informs kernel to run binary 
    ->Kernel allocates memory from the pool to fit the binary image into 
    ->Kernel loads binary into memory 
    ->Kernel jumps to specific memory address 
    ->Kernel starts processing the machine code located at this location 
    ->If machine code has stop 
    ->Kernel releases memory back to pool 

Executable - Shared Library 

Client request to run application 
    ->Shell informs kernel to run binary 
    ->Kernel allocates memory from the pool to fit the binary image into 
    ->Kernel loads binary into memory 
    ->Kernel jumps to specific memory address 
    ->Kernel starts processing the machine code located at this location 
    ->Kernel pushes current location into an execution stack 
    ->Kernel jumps out of current memory to a shared memory location 
    ->Kernel executes code from this shared memory location 
    ->Kernel pops back the last memory location and jumps to that address 
    ->If machine code has stop 
    ->Kernel releases memory back to pool 

JavaScript/.NET/Perl/Python/PHP/Ruby (Interpretted Languages) 

Client request to run application 
    ->Shell informs kernel to run binary 
    ->Kernel has a hook that recognises binary images needs a JIT 
    ->Kernel calls JIT 
    ->JIT loads the code and jumps to a specific address 
    ->JIT reads the code and compiles the instruction into the 
    machine code that the interpretter is running on 
    ->Interpretture passes machine code to the kernel 
    ->kernel executes the required instruction 
    ->JIT then increments the program counter 
    ->If code has a stop 
    ->Jit releases application from its memory pool 

正如routeNpingme所说,寄存器被设置在CPU内部并发生奇迹!

更新:是的,我今天无法正确使用!

21

好的,回答我自己的问题。这将逐步完成,并且只针对Linux(也许Mach-O)。随意添加更多的东西给你的个人答案,让他们得到upvoted(你可以得到徽章,因为它现在是CW)。

我会中途开始,并根据我的发现建立休息。本文档是使用x86_64,gcc(GCC)4.1.2编写的。

打开文件,初始化

在本节中,我们描述的程序被调用时会发生什么,从内核来看,直到程序已准备好执行。

  1. ELF打开。
  2. 内核查找.text部分并将其加载到内存中。将其标记为只读
  3. 内核加载.data节
  4. 内核加载.bss节,并将所有内容初始化为零。
  5. 内核将控制权移交给动态链接程序(其名称位于ELF文件的.interp节中)。动态链接器解析所有共享库调用。
  6. 控制转移到应用程序

程序的执行

  • 功能_start被调用,作为ELF头指定它作为入口点传递以下信息,它

    1. 广告可执行
    2. _start在glibc的__libc_start_main(通过PLT)调用实际主功能

    3. 所述的argc地址
    4. 所述的argv地址的礼服
    5. 的_init例程的地址
    6. 的_fini例程
    7. 一个函数指针为atexit对()注册的地址
    8. 可用的最高堆栈地址
  • _init被称为

    1. 调用call_gmon_start来初始化gmon分析。与执行没有关系。
    2. 电话frame_dummy,它包装__register_frame_info(eh_frame部分地址,BSS部分地址)(FIXME:这是什么功能做初始化一个BSS部分显然全局变量)
    3. 电话__do_global_ctors_aux,其作用是调用所有全局.ctors部分中列出的构造函数。
  • 主要被称为
  • 主要目的
  • _fini被调用,它在原来的呼叫__do_global_dtors_aux作为.dtors部分指定运行所有的析构函数。
  • 该程序退出。
  • 3

    在Windows上,首先将映像加载到内存中。内核分析它将要求的哪些库(读取“DLL”)并加载它们。

    然后编辑程序映像以插入它所需的每个库函数的内存地址。这些地址已经在.EXE二进制文件中有一个空格,但它们只填充了零。

    然后每个DLL的DllMain()过程从最需要的DLL到最后一个被逐个执行,如下面的依赖顺序。

    所有库加载完毕并准备好后,最后会启动图像,现在发生的任何事情都取决于所用的语言,使用的编译器和程序例程本身。

    相关问题