你真的深入理解計算機系統了嗎之篇章三:程序的結構


  計算機中的信息=位+上下文。進一步,信息可以分為兩大類:一類是數據,一類是指令。指令用來表明操作的動作,數據用來表明被操作的對象,這兩者同時也構成了一個完整的程序。

  對於數據而言,我們先來談整數的表示和運算。無符號編碼表示無符號數,補碼表示有符號數,相信大家對這兩種編碼應該是非常熟悉的(無符號編碼沒有符號位,補碼的最高位表示符號位)。

  在整數的運算方面一共有兩種,一種是算術運算,一種是邏輯運算。算術運算就指平常的加減乘數,當然要注意溢出、符號位等各種情況(這個講起來的話太多了,而且我也擔心自己講不好,不懂的讀者可以去翻翻書)。邏輯運算主要包括移位操作、或與非等,對於移位操作,一定要注意是算術右移還是邏輯右移,算法右移在所缺的位置要補齊符號位,邏輯右移要補齊零。

  由於浮點型的表示和運算,我也掌握的不是太好,讀者自己翻書吧。

  對於指令而言,有傳送指令、算術指令、邏輯指令、跳轉指令以及支持過程調用和返回的指令。這些指令與c語言中的結構都是對應的,下面我會為大家講解。

  傳送指令主要是mov a, b這種形式,像c語言中的賦值操作以及取某個變量的值等最后都會轉化為這種指令。傳送指令一共有三種尋址方式。第一種方式為立即數尋址,形式為mov $imm, EM,表示將imm傳送到寄存器或者存儲器EM中;第二種方式為寄存器尋址,形式為mov Ea, EM,表示將寄存器Ea中的值傳送到EM中;第三種為存儲器尋址,形式為mov (Ea), EM,表示將寄存器中的值所表示的存儲器位置的值傳送到EM中,當然這個有很多變形,但本質是一樣的。要注意到不能從存儲器傳送到存儲器。

  在算術和邏輯指令中,像加減乘除、或與非、移位操作自不必說,在c語言中的這些操作與匯編中基本是沒什么區別。我主要來說一下lea,即加載有效地址指令,它是mov指令的變形。指令形式為lea S, D,效果是將S的地址傳送到D中,其中D必須為寄存器,像c語言中的求地址操作&就對應這種匯編語言。例如lea (Ea), Eb,在mov指令中表示將寄存器中的值所表示的存儲器位置的值傳送到Eb中,而在lea指令中表示將寄存器Ea中的值傳送到寄存器Eb中。同時還可以用這個指令來進行一些算術運算。

  跳轉指令主要包括無條件跳轉和有條件跳轉,無條件跳轉的形式為jmp Label或者jmp *Operand,后者的跳轉目標是從寄存器或者存儲器中讀出的。對於有條件跳轉,只有在符合某些條件的情況下才會跳轉,比如je、jne等,那么在匯編中是如何知道這些條件成立不成立呢?除了整數寄存器,CPU還包含一組單個位的條件碼寄存器,比如CF(無符號溢出)、ZF(零)、SF(負數)、OF(有符號溢出),它們描述的是最近操作的屬性,也有一些指令專門用來設置條件碼而不修改其他寄存器,像test、cmp。跳轉指令根據這些條件碼的組合情況來決定是否跳轉。在c語言中像if語言、for語言、while語言、switch語言最終都會翻譯成跳轉指令。

  最后一種指令就是支持過程調用和返回的指令。其中call指令用來過程調用,ret指令用來從過程調用中返回。c語言中的過程最后會翻譯為匯編中的過程調用代碼。在x86系統中一共有8個整數寄存器,其中有兩個寄存器支持過程的實現,分別是棧指針%esp,幀指針%ebp。當執行call Label時(Label表示被調用的標記,也可以是*Operand的形式),計算機將返回地址(調用者的下一條指令地址)入棧,再將幀指針中保存的值(調用者的幀指針)入棧,最后將棧指針中保存的值傳給幀指針,下面就開始執行被調用者中的指令,當執行ret返回時就是call指令的逆序,先將幀指針中保存的值傳給棧指針,再push %ebp,將返回地址更新到程序計數器中,繼續調用函數的執行。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM