windows和linux運行程序的區別

  • 本文摘自牛客:https://www.nowcoder.com/discuss/224797?type=post&order=time&pos=&page=0
    爲什麼同一個程序,在同一臺計算機上,在Linux下可以運行,而在Windows下卻不行呢?
    反過來,Windows上的程序在Linux上也是一樣不能執行的

1編譯、鏈接和裝載:拆解程序執行

一個程序執行的過程是什麼樣的?
如果簡單說,就是編譯器將代碼編譯成彙編代碼,然後彙編代碼再通過彙編器變成機器碼,這樣cpu就可以執行這些機器碼了。
上面的過程簡化了很多,如果詳細分析,要分爲兩個部分:

  • 第一部分編譯、彙編、鏈接的過程,生成一個可執行文件
  • 第二部分通過裝載器把可以執行文件裝載到內存中,cpu從內存中讀取指令和數據,就真正執行了程序。
    在這裏插入圖片描述

2 ELF格式和鏈接

程序最終是通過裝載器變成指令和數據的,所以其實生成的可執行代碼也並不僅僅是一條條的指令。

在Linux下,可執行文件和目標文件所使用的都是一種叫ELF(Execuatable and Linkable File Format)的文件格式,中文名字叫可執行與可鏈接文件格式
這裏面不僅存放了編譯成的彙編指令,還保留了很多別的數據。

ELF文件格式把各種信息,分成一個一個的Section保存起來。ELF有一個基本的文件頭(File Header),用來表示這個文件的基本屬性,比如是否是可執行文件,對應的CPU、操作系統等等。除了這些基本屬性之外,大部分程序還有這麼一些Section:

  • 首先是.text Section,也叫作代碼段或者指令段(Code Section),用來保存程序的代碼和指令;
  • 接着是.data Section,也叫作數據段(Data Section),用來保存程序裏面設置好的初始化數據信息;
  • 然後就是.rel.text Secion,叫作重定位表(Relocation Table)。重定位表裏,保留的是當前的文件裏面,哪些跳轉地址其實是我們不知道的。比如上面的 link_example.o 裏面,我們在main函數裏面調用了 add 和 printf 這兩個函數,但是在鏈接發生之前,我們並不知道該跳轉到哪裏,這些信息就會存儲在重定位表裏;
  • 最後是.symtab Section,叫作符號表(Symbol Table)。符號表保留了我們所說的當前文件裏面定義的函數名稱和對應地址的地址簿。
    鏈接器會掃描所有輸入的目標文件,然後把所有符號表裏的信息收集起來,構成一個全局的符號表。然後再根據重定位表,把所有不確定要跳轉地址的代碼,根據符號表裏面存儲的地址,進行一次修正。最後,把所有的目標文件的對應段進行一次合併,變成了最終的可執行代碼。這也是爲什麼,可執行文件裏面的函數調用的地址都是正確的

3 總結

爲什麼同樣一個程序,在Linux下可以執行而在Windows下不能執行了。其中一個非常重要的原因就是,兩個操作系統下可執行文件的格式不一樣。

我們今天講的是Linux下的ELF文件格式,而Windows的可執行文件格式是一種叫作PE(Portable Executable Format)的文件格式。Linux下的裝載器只能解析ELF格式而不能解析PE格式。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章