本篇是我本人博客中的專題“追根溯源 從C++到匯編”中的開篇。這是我第一次嘗試寫一個系列的文章出來與大家分享。如果有什么疏漏,歡迎大家指正。
為了闡述C++和匯編的關系,我覺著有必要簡單介紹下匯編知識和一些計算機的基本組成。本篇的內容盡量保持簡短。本篇的目的是為了后續的講解做一個基礎性的鋪墊與簡介,點到即止。
本文假定讀者沒有任何匯編基礎知識。如果有讀者對匯編很熟悉,可以略過本篇,參看系列后續的文章。
疑惑:程序到底是怎么執行的
現代計算機自圖靈機理論誕生以來經歷了高速發展。互聯網時代,網絡和移動平臺正在深刻地改變這個社會。作為程序員,我們每天都在產出代碼,這些代碼在特定的平臺和運行時系統支撐下運行,我們都早已習以為常。
但是如果你問一個程序員:你寫的程序為什么能執行?大概他會一愣,然后拋出各種理論:因為編譯器啊,因為jvm運行時啊,因為語言機制啊等等不一而足。其實這個問題就好比你去問一個大學生:1+1=2是個什么原理。也許在程序員看來,“程序為什么能運行”根本就不是問題,或者說算是個哲學問題?
其實很多時候,我們都不會去思考這種問題,因為它太基礎,但是今天,我想嘗試從匯編的角度解釋下這個問題。
從匯編層面解釋程序執行
1. cpu工作原理
這個話題扯開來說很大,我們盡量簡單點理解它。
1.1 機器碼與指令集
我們都知道,cpu是計算機的邏輯運算核心。我們寫的程序代碼,在編譯為二進制后,最終會由cpu來執行(當然,gpu現在也能執行運算,這個我們暫且不表)。那為什么cpu能夠理解二進制的0101代表什么意思?因為cpu指令集。
不同的cpu在設計的時候,就被設計為支持某種指令的編碼格式,我們稱之為cpu指令集。不同的cpu支持不同的指令集。比如我們經常聽到的MMX,SSE,都是指令集的一種。使用軟件可以查詢不同cpu支持的指令集,比如下面一張圖:
可以看到i5處理器已經支持了很多的指令集。
1.2 執行過程
CPU的基本工作是執行存儲的指令序列,即程序。程序的執行過程實際上是不斷地取出指令、分析指令、執行指令的過程。幾乎所有的馮?諾伊曼型計算機的CPU,其工作都可以分為5個階段:取指令、指令譯碼、執行指令、訪存取數和結果寫回。
我們可以簡單理解為,cpu在控制器,存儲器,數據總線等多種部件的協調下,以一種流水線的方式取出要執行的二級制代碼序列,使用內部的指令集來理解并執行每一條指令。這其中又會涉及到指令周期,時鐘周期,cpu主頻等概念。一個cpu的內部結構圖大概如下圖所示:
2. x86匯編和二進制機器碼
按照前面我們所說,不同的cpu支持不用的指令集(其實這里的概念應該從架構上來說)。也就是說,不同的cpu架構其實存在不同的匯編語言。在pc上廣泛使用的cpu架構和匯編是intel公司的80x86系列和對應的x86匯編。
匯編指令可以通過匯編編譯器翻譯成對應的二進制指令,進而由cpu直接執行。匯編指令和二進制機器碼直接對應,可以通過查閱intel的cpu技術文檔了解這種對應關系的具體細節。
3. 寄存器的概念和x86 cpu中的寄存器
關于寄存器的基本概念,百度百科是這樣解釋的
在計算機領域,寄存器是CPU內部的元件,包括通用寄存器、專用寄存器和控制寄存器。寄存器擁有非常高的讀寫速度,所以在寄存器之間的數據傳送非常快。
寄存器是內存階層中的最頂端,也是系統獲得操作資料的最快速途徑。
簡單點理解,寄存器是最高速的內存單元,與cpu直連,擁有最快的訪問和存取速度。我們一般意義上的內存,比之寄存器,速度上就沒得比了。寄存器的意義在于,為cpu提供了一種快速速度存取途徑,加速了cpu的運行速度。
32位CPU所含有的寄存器如下:
4個數據寄存器(EAX、EBX、ECX和EDX)
2個變址和指針寄存器(ESI和EDI)
2個指針寄存器(ESP和EBP)
6個段寄存器(ES、CS、SS、DS、FS和GS)
1個指令指針寄存器(EIP)
1個標志寄存器(EFlags)
這些寄存器的作用,在此不做詳細解釋。在x86匯編中,我們會直接使用這些寄存器來進行運算。因為本篇并不是一個x86匯編的教學帖,我們會在后面的講解中對用到的寄存器做一些補充說明。
結束語
本篇在此打住,也許各位看官仍然有很多不理解的部分,因為本篇的介紹實在是有些過于簡單。但是相信我,我們的主題從來都不是機器碼,二進制,匯編。我們會在后續的章節中,探究一些關于C++語言層面的問題,又或者是一些代碼安全問題。我會努力把更多精彩的文章帶給大家,我們拭目以待。