运行程序会发生什么?

Ste*_*ini 38 linux execution

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

编辑:问题现在是CW.我正在填写linux.如果有人想为Win和OSX做同样的事情那就太棒了.

Way*_*yne 34

当然,这只是一个非常高的抽象层次!

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
Run Code Online (Sandbox Code Playgroud)

正如routeNpingme所说,寄存器设置在CPU内部并且魔术发生了!

更新:是的,我今天不能正确拼写!


Ste*_*ini 25

好的,回答我自己的问题.这将逐步完成,仅适用于Linux(也许是Mach-O).随意添加更多的东西到你的个人答案,以便他们得到投票(你可以获得徽章,因为它现在是CW).

我会中途开始,然后在我发现的时候建立其余部分.本文档使用x86_64,gcc(GCC)4.1.2.

打开文件,初始化

在本节中,我们将描述从内核的角度调用程序时会发生什么,直到程序准备好执行.

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

执行程序

  1. 函数_start被调用,因为ELF头指定它作为可执行文件的入口点
  2. _start在glibc中调用__libc_start_main(通过PLT)将以下信息传递给它

    1. 实际主要功能的地址
    2. argc地址
    3. argv地址
    4. _init例程的地址
    5. _fini例程的地址
    6. atexit()注册的函数指针
    7. 可用的最高堆栈地址
  3. _init被调用

    1. 调用call_gmon_start来初始化gmon分析.与执行没有关系.
    2. 调用frame_dummy,它包装__register_frame_info(eh_frame节地址,bss节地址)(FIXME:这个函数做什么?显然从BSS节初始化全局变量)
    3. 调用__do_global_ctors_aux,其作用是调用.ctors部分中列出的所有全局构造函数.
  4. 主被叫
  5. 主要目的
  6. 调用_fini,然后调用__do_global_dtors_aux来运行.dtors部分中指定的所有析构函数.
  7. 程序退出.


Hav*_*ard 5

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

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

然后,每个 DLL 的 DllMain() 过程都会从最需要的 DLL 到最后一个逐个执行,就像遵循依赖关系的顺序一样。

一旦所有库都加载并准备就绪,最终映像就会启动,现在发生的任何事情都将取决于所使用的语言、所使用的编译器以及程序例程本身。


Max*_*ing 0

好吧,根据您的具体定义,您必须考虑 .Net 和 Java 等语言的 JIT 编译器。当您运行技术上不可“执行”的 .Net“exe”时,JIT 编译器会介入并编译它。

  • .Net 运行时是一个可执行文件...它运行整个虚拟环境并优化字节码这一事实是无关紧要的。 (3认同)