Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Java Bytecode 101

Java Bytecode 101

1bc80e2eee2adeaa8bb577798d92e9d0?s=128

Anton Arhipov

October 15, 2016
Tweet

Transcript

  1. Байткод для любознательных @antonarhipov Joker 2016, СПб

  2. @antonarhipov Антон Архипов

  3. Зачем? • Знай свою платформу! • Хотите написать свой компилятор?

    • Фреймворки (AOP, ORM) • Всевозможные инструменты (см. JRebel) • … ну или может просто скучно?
  4. Основы Java-байткода Инструментарий ObjectWeb ASM

  5. 1 + 2

  6. 1 + 2 1 2 +

  7. 1 + 2 1 2 +

  8. 1 + 2 1 2 + PUSH 1 1

  9. 1 + 2 1 2 + PUSH 1 PUSH 2

    2 1
  10. 1 + 2 1 2 + PUSH 1 PUSH 2

    ADD 3
  11. 1 + 2 1 2 + ICONST_1 ICONST_2 IADD 3

  12. ? = 1 + 2

  13. Таксономия

  14. Работа со стеком Таксономия

  15. Работа со стеком Инструкции управления Таксономия

  16. Работа со стеком Инструкции управления Работа с объектами Таксономия

  17. Работа со стеком Инструкции управления Арифметика Работа с объектами Таксономия

  18. Работа со стеком Инструкции управления Арифметика Работа с объектами monitorenter

    monitorexit Таксономия
  19. Байт-код • Одно-байтные инструкции • 256 возможных вариантов • Используется

    200+ • Google: “Java bytecode instructions listings” • https://en.wikipedia.org/wiki/Java_bytecode_instruction_listings
  20. • <тип> ::= b, s, c, i, l, f, d,

    a • Константы (ldc, iconst_1) • Локальные переменные и стек (load/store) • Операции с массивами (aaload, aastore) • Арифметика (add, sub, mul, div) • Булевые/битовые операции (iand, ixor) • Сравнения (cmpg, cmpl, ifne, ifeq) • Преобразования (l2d, i2l) ОПЕРАЦИЯ ТИП
  21. None
  22. JVM процесс

  23. Thread 1 Thread 2 Thread 3 Thread 4

  24. None
  25. • JVM работает со стеком • У каждого потока есть

    стек • Стек сохраняет “фреймы” • Новый “фрейм” создаётся при вызове метода • “Фрейм” состоит из: – Стек операций – Массив локальных переменных Стековая машина
  26. Стек операций Локальные переменные 2 0 1 N … Константы

    #1
  27. Работа со стеком и локальными переменными

  28. A B dup pop swap dup_x1 dup2_x1

  29. A B dup pop swap dup_x1 dup2_x1 A

  30. dup pop swap dup_x1 dup2_x1 A B

  31. dup pop swap dup_x1 dup2_x1 A B

  32. dup pop swap dup_x1 dup2_x1 A B B

  33. dup pop swap dup_x1 dup2_x1 A B B B A

  34. ldc "Hello" astore_0 iconst_1 astore_1 aload_0 глубина значение Стек переменная

    значение Локальные переменные 0 1 2 3 4 0 1 2 3 4
  35. ldc "Hello" astore_0 iconst_1 astore_1 aload_0 "Hello" 0 1 2

    3 4 0 1 2 3 4 глубина значение переменная значение Стек Локальные переменные
  36. ldc "Hello" astore_0 iconst_1 astore_1 aload_0 "Hello" 0 1 2

    3 4 0 1 2 3 4 глубина значение переменная значение Стек Локальные переменные
  37. ldc "Hello" astore_0 iconst_1 astore_1 aload_0 "Hello" 0 1 2

    3 4 0 1 2 3 4 1 глубина значение переменная значение Стек Локальные переменные
  38. ldc "Hello" astore_0 iconst_1 astore_1 aload_0 "Hello" 0 1 2

    3 4 0 1 2 3 4 1 глубина значение переменная значение Стек Локальные переменные
  39. ldc "Hello" astore_0 iconst_1 astore_1 aload_0 "Hello" 0 1 2

    3 4 0 1 2 3 4 1 "Hello" глубина значение переменная значение Стек Локальные переменные
  40. Стек Таблица локальных переменных store load

  41. Вызовы методов

  42. invokeXXX • invokestatic • invokespecial • invokevirtual • invokeinterface •

    invokedynamic
  43. invokestatic • invokestatic • invokespecial • invokevirtual • invokeinterface •

    invokedynamic Integer.valueOf(“42”)
  44. invokespecial • invokestatic • invokespecial • invokevirtual • invokeinterface •

    invokedynamic <init> private void foo(); super.method();
  45. • invokestatic • invokespecial • invokevirtual • invokeinterface • invokedynamic

    invokevirtual class A class B A/method1 A/method2 A/method1 B/method2 B/method3
  46. invokeinterface • invokestatic • invokespecial • invokevirtual • invokeinterface •

    invokedynamic Efficient Implementation of Java Interfaces: Invokeinterface Considered Harmless, Bowen Alpern, Anthony Cocchi, Stephen Fink, David Grove, and Derek Lieber, OOPSLA’01 class A class B impl X A/method1 A/method2 A/method1 B/method2 B/method3 X/methodX D impl X D/method1 X/methodX
  47. Вызов метода

  48. obj.method(param1, param2); Вызов метода

  49. obj.method(param1, param2); Вызов метода

  50. obj.method(param1, param2); push obj push param1 push param2 call method

    Вызов метода
  51. obj.method(param1, param2); push obj push param1 push param2 call method

    obj Вызов метода
  52. obj.method(param1, param2); push obj push param1 push param2 call method

    obj param1 Вызов метода
  53. obj.method(param1, param2); push obj push param1 push param2 call method

    obj param1 param2 Вызов метода
  54. obj.method(param1, param2); push obj push param1 push param2 call method

    obj? Вызов метода
  55. this.add(1, 2); 0: aload_0 1: iconst_1 2: iconst_2 3: invokevirtual

    #2; //Method add:(II)I Вызов метода
  56. Стек pop push

  57. Стек Таблица локальных переменных store load pop push

  58. Стек Таблица локальных переменных store load pop push

  59. Стек Таблица локальных переменных store load pop push Стек Таблица

    локальных переменных store load pop push invoke
  60. None
  61. public class Hello {
 public static void main(String[] args) {


    System.out.println("Hello, World!");
 }
 }
  62. public class Hello {
 public static void main(String[] args) {


    System.out.println("Hello, World!");
 }
 } > javap -c Hello Дизассемблировать Hello
  63. public class Hello {
 public static void main(String[] args) {


    System.out.println("Hello, World!");
 }
 } > javap -c Hello javap • Дизассемблер Java класс-файлов • По-умолчанию показывает только структуру класса – Методы, супер-класс, интерфейсы, итд • -c покажет байткод методов • -private покажет все приватные поля и методы • -s покажет сигнатуры • -l покажет номера строк и таблицу локальных переменных
  64. public class Hello {
 public static void main(String[] args) {


    System.out.println("Hello, World!");
 }
 } > javap -c Hello Compiled from "Hello.java" public class Hello extends java.lang.Object{ public Hello(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return
  65. > javap -c Hello Compiled from "Hello.java" public class Hello

    extends java.lang.Object{ public Hello(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return Конструктор по умолчанию public class Hello {
 public static void main(String[] args) {
 System.out.println("Hello, World!");
 }
 }
  66. > javap -c Hello Compiled from "Hello.java" public class Hello

    extends java.lang.Object{ public Hello(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return Выложить this на стек public class Hello {
 public static void main(String[] args) {
 System.out.println("Hello, World!");
 }
 }
  67. > javap -c Hello Compiled from "Hello.java" public class Hello

    extends java.lang.Object{ public Hello(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return Вызвать <init> для Object public class Hello {
 public static void main(String[] args) {
 System.out.println("Hello, World!");
 }
 }
  68. public class Hello {
 public static void main(String[] args) {


    System.out.println("Hello, World!");
 }
 } > javap -c Hello Compiled from "Hello.java" public class Hello extends java.lang.Object{ public Hello(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return
  69. public class Hello {
 public static void main(String[] args) {


    System.out.println("Hello, World!");
 }
 } > javap -c Hello Compiled from "Hello.java" public class Hello extends java.lang.Object{ public Hello(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3; //String Hello, World! 5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
  70. > javap -c Hello Compiled from "Hello.java" public class Hello

    extends java.lang.Object{ public Hello(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3; //String Hello, World! 5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V Обратиться к статическому полю public class Hello {
 public static void main(String[] args) {
 System.out.println("Hello, World!");
 }
 }
  71. > javap -c Hello Compiled from "Hello.java" public class Hello

    extends java.lang.Object{ public Hello(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3; //String Hello, World! 5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V Загрузить строковую константу в стек public class Hello {
 public static void main(String[] args) {
 System.out.println("Hello, World!");
 }
 }
  72. > javap -c Hello Compiled from "Hello.java" public class Hello

    extends java.lang.Object{ public Hello(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3; //String Hello, World! 5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V Вызвать метод с параметром public class Hello {
 public static void main(String[] args) {
 System.out.println("Hello, World!");
 }
 }
  73. public class Hello {
 public static void main(String[] args) {


    System.out.println("Hello, World!");
 }
 } > javap -c Hello Compiled from "Hello.java" public class Hello extends java.lang.Object{ public Hello(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3; //String Hello, World! 5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
  74. > javap -c Hello Compiled from "Hello.java" public class Hello

    extends java.lang.Object{ public Hello(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3; //String Hello, World! 5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V Что такое #1,#2, итд ? public class Hello {
 public static void main(String[] args) {
 System.out.println("Hello, World!");
 }
 }
  75. public class Hello {
 public static void main(String[] args) {


    System.out.println("Hello, World!");
 }
 } > javap -c -verbose Hello
  76. public class Hello {
 public static void main(String[] args) {


    System.out.println("Hello, World!");
 }
 } > javap -c -verbose Hello Compiled from "Hello.java“ public class Hello extends java.lang.Object SourceFile: "Hello.java" minor version: 0 major version: 50 Constant pool: const #1 = Method #6.#20; // java/lang/Object."<init>":()V const #2 = Field #21.#22; // java/lang/System.out:Ljava/io/PrintStream; const #3 = String #23; // Hello, World! const #4 = Method #24.#25; // java/io/PrintStream.println:(Ljava/lang/String;)V const #5 = class #26; // Hello const #6 = class #27; // java/lang/Object const #7 = Asciz <init>;
  77. public class Hello {
 public static void main(String[] args) {


    System.out.println("Hello, World!");
 }
 } > javap -c -verbose Hello Compiled from "Hello.java“ public class Hello extends java.lang.Object SourceFile: "Hello.java" minor version: 0 major version: 50 Constant pool: const #1 = Method #6.#20; // java/lang/Object."<init>":()V const #2 = Field #21.#22; // java/lang/System.out:Ljava/io/PrintStream; const #3 = String #23; // Hello, World! const #4 = Method #24.#25; // java/io/PrintStream.println:(Ljava/lang/String;)V const #5 = class #26; // Hello const #6 = class #27; // java/lang/Object const #7 = Asciz <init>;
  78. public class Hello {
 public static void main(String[] args) {


    System.out.println("Hello, World!");
 }
 } > javap -c -verbose Hello public class Hello extends java.lang.Object … public Hello(); Code: Stack=1, Locals=1, Args_size=1 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 1: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LHello;
  79. public class Hello {
 public static void main(String[] args) {


    System.out.println("Hello, World!");
 }
 } > javap -c -verbose Hello public class Hello extends java.lang.Object … public Hello(); Code: Stack=1, Locals=1, Args_size=1 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 1: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LHello;
  80. public class Hello {
 public static void main(String[] args) {


    System.out.println("Hello, World!");
 }
 } > javap -c -verbose Hello public class Hello extends java.lang.Object … public Hello(); Code: Stack=1, Locals=1, Args_size=1 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 1: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LHello;
  81. public class Hello {
 public static void main(String[] args) {


    System.out.println("Hello, World!");
 }
 } > javap -c -verbose Hello public class Hello extends java.lang.Object … public Hello(); Code: Stack=1, Locals=1, Args_size=1 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 1: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LHello;
  82. None
  83. Java Bytecode Editor — http://set.ee/jbe/

  84. IntelliJ IDEA: ASM Bytecode Outline plugin

  85. public java.lang.String getName(); Code: Stack=1, Locals=1, Args_size=1 0: aload_0 1:

    getfield #2; //Field name:Ljava/lang/String; 4: areturn LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LGet; public class Get {
 String name; 
 public String getName() {
 return name;
 }
 }
  86. aload_0 getfield 00 02 areturn 0 1 2 3 4

    public java.lang.String getName(); Code: Stack=1, Locals=1, Args_size=1 0: aload_0 1: getfield #2; //Field name:Ljava/lang/String; 4: areturn LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LGet;
  87. 2A B4 public java.lang.String getName(); Code: Stack=1, Locals=1, Args_size=1 0:

    aload_0 1: getfield #2; //Field name:Ljava/lang/String; 4: areturn LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LGet; 00 02 0 1 2 3 4 B0
  88. public java.lang.String getName(); Code: Stack=1, Locals=1, Args_size=1 0: aload_0 1:

    getfield #2; //Field name:Ljava/lang/String; 4: areturn LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LGet;
  89. None
  90. ObjectWeb ASM • Низкоуровневый фреймворк для манипуляций и анализа Java-байткода

    • Стандарт de facto • http://asm.ow2.org
  91. None
  92. Зачем манипулировать байткодом (ещё раз) • Профилировщики • Агенты для

    мониторинга • Дебаггеры • Фреймворки • JRebel Требуется внедрение функциональности в работающий код
  93. ASM: общий сценарий Создать ClassWriter Скомпоновать visitor-ы: аннотации, поля, методы,

    итд Генерировать новый байткод 1 2 3
  94. Class Reader Class Visitor

  95. Class Writer Class Visitor Class Visitor Class Reader

  96. Class Writer Class Visitor Class Visitor Class Reader Class Visitor

    Class Visitor
  97. Class Writer Class Visitor Class Visitor Class Reader Class Visitor

    Class Visitor Class Visitor Class Visitor Class Visitor Class Visitor Class Visitor Class Reader Class Writer
  98. ClassVisitor visit visitSource visitOuterClass visitAnnotation visitAttribute visitInnerClass visitField visitMethod visitEnd

    ClassReader
  99. ClassVisitor visit visitSource visitOuterClass visitAnnotation visitAttribute visitInnerClass visitField visitMethod visitEnd

    AnnotationVisitor FieldVisitor MethodVisitor ClassReader
  100. None
  101. https://github.com/antonarhipov/asmdemo

  102. None