踏上 Java 字節碼世界之旅?本文涵蓋了入門所需了解的所有內容。
早在 1995 年,Java 程式設計的創建者 Sun Microsystems語言,提出了大膽的主張。他們說 Java 可以讓你「寫一次,隨處運行」。這意味著編譯後的二進位檔案將能夠在任何系統架構上運行,這是 C 無法做到的,並且至今仍然是編寫 Java 的核心租戶。
為了實現這種跨平台功能,Java 採用了編譯時採用獨特的方法。 Java 不是將原始程式碼直接轉換為機器碼(機器碼特定於每個系統架構),而是將其程式編譯為稱為字節碼的中間形式。字節碼是一組指令,既不依賴特定的機器語言,也不依賴任何特定的硬體架構。這種抽像是Java可移植性的關鍵。
解釋和執行Java字節碼指令的程式稱為Java虛擬機器(JVM)。 JVM 將每個字節碼指令翻譯成其運作所在的特定係統架構本機的機器碼。此過程通常稱為「即時」(JIT) 編譯,允許 Java 字節碼在任何給定平台上盡可能有效率地執行。
字節碼是不過,它不僅僅對 JVM 有用。由於 Java 類別的字節碼有助於逆向工程、效能最佳化、安全研究和其他靜態分析功能,因此 JDK 附帶了實用程式來幫助您和我檢查它。
看一下以下範例字節碼,請考慮以下來自`java.lang.Boolean`、`booleanValue` 和`valueOf(boolean)` 的兩個方法,它們分別對`boolean` 原始型別進行拆箱和裝箱:
public boolean booleanValue() { return value; } public static Boolean valueOf(boolean b) { return (b ? TRUE : FALSE); }
使用` javap` 指令是JDK 附帶的,我們可以看到每個指令的字節碼。您可以透過使用“-c”命令和類別的完全限定名稱來執行“javap”來完成此操作,如下所示:
javap -c java.lang.Boolean
結果是“中所有公共方法的字節碼” java .lang.Boolean`。這裡我只複製了`booleanValue` 和`valueOf(boolean)` 的字節碼:
public boolean booleanValue(); code: 0: aload_0 1: getfield #7 // Field value:Z 4: ireturn public static java.lang.Boolean valueOf(boolean); Code: 0: iload_0 1: ifeq 10 4: getstatic #27 // Field TRUE:Ljava/lang/Boolean; 7: goto 13 10: getstatic #31 // Field FALSE:Ljava/lang/Boolean; 13: areturn
乍一看,這是一門全新的需要學習的語言。然而,當您了解每個指令的作用以及 Java 使用堆疊進行操作時,它很快就會變得簡單。
以 `booleanValue` 的三個字節碼指令為例:
`aload_n` 表示將局部變數的參考放入堆疊。在類別實例中,`aload_0` 引用 `this`。
`getfield` 表示從`this`(堆疊中最下面的一項)讀取成員變數並將其放置將值入堆疊
`#7`指引用在常數池中的索引
`//字段值:Z`告訴我們`#7`指的是一個名為`value`的`boolean`類型的欄位(Z)
`ireturn`表示彈出一個原始值從堆疊中取出並傳回它
長話短說,這三個指令尋找實例的「value」欄位並傳回它。
作為第二個範例,採用看下一個方法, `valueOf(boolean)`:
`iload_n` 堆疊表示將一個原始局部變數放入堆疊中意味著。 `iload_0` 指的是第一個方法參數(因為第一個方法參數是一個原語)
`ifeq n` 表示將值從堆疊中彈出並查看是否為true;如果是,則繼續到下一行,否則跳到行`n`
`getstatic #n` 表示將靜態成員讀取到堆疊
`#27` 指的是常數池中靜態成員的索引
`// 字段TRUE:Ljava/lang/Boolean` 告訴我們`#27`指的是什麼,類型為`Boolean
`goto n` 的靜態成員名為`TRUE` 表示現在跳到字節碼中的` n` 行
`areturn` 表示從堆疊中彈出引用並返回它
換句話說,這些說明說,如果為true ,則採用第一個方法參數,然後傳回`Boolean.TRUE`;否則,傳回`Boolean.FALSE`。
我之前提到這對於逆向工程、效能最佳化和安全研究很有幫助。現在讓我們擴展一下這些內容。
使用第三方函式庫或閉源元件時,字節碼分析成為一個強大的工具。反編譯字節碼可以讓您了解這些函式庫的內部工作原理,有助於整合、故障排除並確保相容性。
在遇到專有或閉源 Java 程式碼的情況下,讀取字節碼可能是唯一可行的方法的方式來了解其功能。字節碼分析可讓您進行逆向工程並理解閉源應用程式的行為,從而促進互通性或自訂。
舉一個現實生活中的例子,我最近嘗試將第三方包纏結分析工具整合到我們的 Ci 系統中。不幸的是,該供應商是閉源的,並且只有有關如何透過其專有 UI 存取該庫的文檔。透過分析字節碼,我能夠對底層分析引擎的預期輸入和輸出進行逆向工程。
以上是如何閱讀 Java 字節碼既有趣又有利可圖的詳細內容。更多資訊請關注PHP中文網其他相關文章!