当你运行一个程序时会发生什么?

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

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


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

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内部并发生奇迹!

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


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

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

打开文件,初始化

在本节中,我们描述从内核的角度调用程序时发生的情况,直到程序准备好执行。

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

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

  • 实际主要功能的地址
  • argc地址
  • argv地址
  • _init例程的地址
  • _fini例程的地址
  • atexit()注册的函数指针
  • 可用的最高堆栈地址
  • _init被调用

  • 调用call_gmon_start来初始化gmon分析。 与执行没有关系。
  • 调用frame_dummy,它封装了__register_frame_info(eh_frame节地址,bss节地址)(FIXME:这个函数做什么?显然是从BSS节初始化全局变量)
  • 调用__do_global_ctors_aux,其作用是调用.ctors节中列出的所有全局构造函数。
  • 主要被称为
  • 主要目的
  • _fini被调用,依次调用__do_global_dtors_aux运行.dtors部分中指定的所有析构函数。
  • 该程序退出。

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

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

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

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

    链接地址: http://www.djcxy.com/p/67775.html

    上一篇: What happens when you run a program?

    下一篇: Animation synching, cursor and highlight