官术网_书友最值得收藏!

基于棧的指令集架構

在匯編語言中,除直接內存操作的指令外,其它指令的執行都依賴寄存器,如跳轉指令、循環指令、加減法指令等。匯編指令集是由硬件直接支持的,不同架構的CPU提供的匯編指令集也會不一樣[1]

以一個經典的++i面試題為例,使用c語言編寫的實現如下。

int m = ++i;

反匯編后對應的32位x86 CPU的匯編指令如下。

inc dword ptr [ebp-44h]
mov eax,dword prt [ebp-44h]
mov dword ptr [ebp-4ch],eax

這三條指令的意思是,先將[ebp-44h]指向的內存塊的值加1,dword ptr相當于c語言中的類型聲明。接著將自增后[ebp-44h]指向的內存塊的值放入eax寄存器,最后將eax寄存器的值放到[ebp-4ch]指向的內存塊,也就是賦值給變量m。由于i和m是在棧上分配的內存,因此[ebp-44h]對應i的內存地址,[ebp-4ch]對應m的內存地址。

匯編指令不能直接操作將一塊內存的值賦值給另一塊內存,必須要通過寄存器。32位x86 CPU包括8個通用寄存器,EAX、EBX、ECX、EDX、ESP、EBP、ESI、EDI,其中EBP、ESP用做指針寄存器,存放堆棧內存儲單元的偏移量[2]。這些看不懂沒關系,這也不是本書的重點。

上述++i的例子使用java代碼實現如下。

public static void main(String[] args) {
    int a = 10;
    int result = ++a;
    System.out.println(result);
}

使用javap命令輸出這段代碼的字節碼如下。

public static void main(java.lang.String[]);
    Code:
       0: bipush        10
       2: istore_1
       3: iinc          1, 1
       6: iload_1
       7: istore_2
       8: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
     11: iload_2
     12: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
     15: return 

字節碼指令前面的編號我們暫時理解為行號。在本例中,行號0到7的字節碼指令完成的工作是將變量a自增后的值賦值給result變量。下面將詳細分析這幾條指令的執行過程。

1. bipush指令是將立即數10放入到操作數棧頂,如圖1.10所示。

圖1.10 bipush指令執行過程

2. istore_1指令是將操作數棧頂的元素從操作數棧出彈出,并存放到局部變量表中索引為1的Slot,也就是賦值給變量a。如圖1.11所示。

圖1.11 istore指令執行過程

3. iinc這條字節碼指令比較特別,它可以直接操作局部變量表的變量,而不需要經過操作數棧。該指令是將局部變量表中索引為1的Slot所存儲的整數值自增1,也就是將局部變量a自增1。如圖1.12所示。

圖1.12 iinc指令執行過程

4. iload_1指令是將自增后的變量a放入操作數棧的棧頂,如圖1.13所示。

圖1.13 iload_1指令執行過程

5. 最后,istore_2指令是將當前操作數棧頂的元素從操作數棧彈出,并存放到局部變量表中索引為2的Slot,也就是給result變量賦值。如圖1.14所示。

圖1.14 istore_2指令執行過程

從++i的例子中,我們可以看出,字節碼是依賴操作數棧工作的。在虛擬機上執行的字節碼指令雖然最終也是編譯為機器碼執行,但編寫字節碼指令時并不需要我們考慮使用哪些寄存器的問題,這些交由JVM去實現。

使用匯編指令編寫代碼,我們需要考慮CPU的架構,有多少個寄存器可選,了解硬件,需要關心每條指令操作多少個字節,在使用寄存器之前需要考慮是否要備份寄存器的當前值,指令執行完之后是否需要恢復寄存器的值。而使用依賴棧工作的字節碼指令編寫代碼,我們只需要關心每條字節碼指令需要多少個參數,按順序將參數push到操作數棧頂。如果指令執行完有返回值,操作數棧頂就是返回值。


注釋:

[1] cpu架構是cpu廠商給屬于同一系列的cpu產品定的一個規范

[2] 王爽.《匯編語言》

主站蜘蛛池模板: 新建县| 丹阳市| 永昌县| 磐安县| 筠连县| 榆树市| 姚安县| 红桥区| 辽源市| 武义县| 罗山县| 湟中县| 高尔夫| 淮南市| 敦化市| 昌都县| 米泉市| 溧水县| 恩平市| 冕宁县| 镇坪县| 汉寿县| 聊城市| 黎川县| 炎陵县| 石台县| 克拉玛依市| 莱州市| 湖南省| 县级市| 饶平县| 宁津县| 石狮市| 泸水县| 抚顺市| 榕江县| 烟台市| 新源县| 湖南省| 永和县| 宁化县|