在高級語言中,變量和數值操作是很基本的語法,基本所有語言都有,但是其在匯編級別上是怎么實現的?或者拓展了說,在計算機上,變量和數值操作的實現邏輯是怎樣的?
主要內容
-
匯編與機器碼
首先,我們要知道,在計算機架構中,最重要的兩層抽象是指令集和虛擬內存。前者是所有計算機程序的最小邏輯單元,即所有的計算機程序,都會被轉換為一連串的計算機指令并運行。而虛擬內存則是計算機對程序可訪問內存的一層抽象,因為這層抽象存在,每一個運行在計算機上的程序可以認為內存是一個只有自己和OS在使用超級大的字節數據。而計算機上存儲、使用的數據都是二進制數(機器碼)的形式,因此,所有的計算機指令都會被轉換為對應的二進制數,計算機最終會根據這些不同的二進制數執行相應的計算機指令。但是二進制數是機器的語言,如果我們要直接使用二進制數進行編程,先不提各個機器上的相同指令對應機器碼之間的差異性和代碼的可讀性問題,記憶各個指令對應的二進制數無疑是困難的。而如果我們設計一種人類可以很容易理解、記憶的語言,它與計算機指令有一一對應的關系,而我們只要再創建一個計算機指令編譯器,將這種新語言轉換對應的機器碼,即解決了上述提到的各個問題。
而匯編語言就是上面說的“新語言”,它只是對各個計算機指令二進制數的簡單字符抽象,匯編語言的格式與編譯器最終轉換為的二進制數形式數據并沒太大區別。下面是一個簡單的代碼實例:
【待補充】 -
數據類型
在計算機上沒有常規意義的數據類型的概念,即沒有Integer,String類型之分。在 匯編語言中,只存在不同長度的二進制數,但是使用二進制數時,指令參數只有以下三種:- 標量,例如
$1
,$22
,當它出現在指令參數時,參數的值就是其對應的二進制數,$
符號只是在匯編的寫法習慣,在實際的二進制代碼中并不存在$
前綴。 - 寄存器,例如
%rax
,%rsi
,當它出現在指令參數時,表示的值為存儲在寄存器中的二進制數。和上面的標量表示一樣,匯編的寫法上一般會在寄存器名前加上%
做為標識。使用寄存器作為參數時,需要注意,當指令要操作不同長度的二進制數時,我們要使用對應長度的寄存器名。例如,寄存器%rax
的64位、32位、16位和8位的名稱分別為%rax
,%eax
,%ax
,%al
,那么當計算機指令操作16位數據時,需要用%ax
標識該寄存器,8位則使用%al
,需要與指令類型嚴格一致。
圖片來自《深入理解計算機系統》- 內存數據,例如
0x100
,(%rdi)
,當指令參數沒有$|%
前綴時,那么他就表示的是存放在內存某個位置的二進制數。這個時候,該二進制數的長度只取決于指令類型。()
表示的是一種特殊的內存地址計算規則,計算規則為:匯編語言內存計算.PNG100(, %rdi, 2)
,其中%rdi
的值為0x1
,則最終結果為100 + 1 * 2 = 102
,即內存地址為102。
- 標量,例如
訪問數據(未完)
算術邏輯操作
思考:
- 在匯編語言中,如何表示高級語言中的變量?
在高級語言中,變量往往就代表著程序的操作對象,可以作為計算結果的存儲地點、程序的操作對象,甚至可以表示一段程序的執行過程。但是對于匯編語言來說,不管是可操作的數據,還是計算機指令本身,都只是一連串的二進制數,這些二進制數的具體含義,僅依賴于其在匯編程序中的上下文(指令類型及參數位置)。
但是在匯編語言中并不存在變量的概念,匯編語言的操作對象是各個寄存器和內存數據,那么匯編語言是怎么表示高級語言中變量的語義的呢?
我們先看一段代碼,對于C語言函數:
其轉換的匯編語言可能是這樣的:void concat_char(char a, char b, char *dest){ dest[0] = a; dest[1] = b; }
上面的匯編代碼中,movb表示移動一個字節,參數有兩個,第一個參數為源地址,第二個參數為目標地址。從上面匯編代碼可以看出,對于匯編語言,不同的參數類型只代表著不同的數據大小。concat_char: movb %dil, (%rdx) %dil表示第一個參數所在的寄存器,%rdx表示第三個參數所在寄存器地址,由于第三個參數是指針,因此需要加上()表示取其指向的內存地址 movb %sil, (%rdx, $1, 1) %sil表示第二個參數所在的寄存器,$1表示標量,即$1就表示了數值1,(%rdx, $1, 1)的語義為(%rdx + 1 * 1)指向的內存地址 ret 表示函數結束
即使考慮更復雜的變量類型 ---- JAVA中的對象,其存儲于計算機中也只是一連串的二進制數據,對于匯編語言來說也只有使用上的區別,即JVM轉換為機器碼時,可能會以不同的指令(同一類型指令,但是操作不同大小的數據)去操作對應對象數據的各個一部分(對應著對象實例的不同的字段類型),但是變量本身卻只對應著某個寄存器或某個內存地址。
總的來說,我們或許可以這樣認為,在匯編語言并不存在變量的概念,但是我們可以通過操作不同數據大小的不同指令,結合寄存器和內存地址來模擬實現變量的效果。