2009-07-30 463 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到最後一個被逐個執行,如下面的依賴順序。

    所有庫加載完畢並準備好後,最後會啓動圖像,現在發生的任何事情都取決於所用的語言,使用的編譯器和程序例程本身。

    相關問題