Something about Bytecode


thật ra bài này phải nói về cấu trúc của file class thì đúng hơn, nhưng cũng chẳng có gì khác nhau hết, vốn dĩ chúng nó là những thứ thuộc về nhau.
* Cấu trúc của một class file:
Mỗi định dạng có một cấu trúc riêng biệt và nhất định, theo thời gian chúng thay đổi thì trình truy xuất dữ liệu từ chúng cũng nâng cấp những phiên bản mới hơn. Điều này cũng giống như bản chất của một con người, dù có thể thay đổi hình dạng đên đâu thì cũng không thể nào thay đổi được chính con người mình, bạn có thể đổi tên từ a.class sang a.txt thì sao, nó vẫn là một file class, chỉ có cái là người ta không nhận bản chất nó khi chỉ nhìn từ cái tên.
[class]
-4b [magic header] mặc định khi chuyển qua hex là CA FE BA BE
-2b [minor version] số nguyên của version x.
-2b [major version] phần thập phân của version .x
-2b [số constant pool] các hằng sẵn có để sử dụng trong class
- [mảng constant pool] bắt đầu 1b chỉ loại, và tùy loại thì:
            .1:chuỗi,  2b độ dài chuỗi a, ab dữ liệu chuỗi
            .3: số nguyên int: 4b giá trị số nguyên
            .4: số thập phân float: 4b giá trị số
            .5: số nguyên long: 8b giá trị số
            .6: số thập phân double: 8b giá trị số
            .7: kiểu class: 2b chỉ đến index của một constant chuỗi tên class trong mảng
            .8: chuỗi sử dụng trong method: 2b chỉ đến index của một consant chuỗi trong mảng
            .9: gọi biến dùng trong method, 2b chỉ đến index kiểu class, 2b chỉ đến kiểu bổ nghĩa
            .10. gọi method dùng trong method, 2b chỉ đến index kiểu class, 2b chỉ đến kiểu bổ nghĩa
            .11: gọi interface method dùng trong method, tương tự kiểu 10
            .12: bổ nghĩa, gồm tên và kiểu, 2b tên chỉ đến kiểu chuỗi (1), 2b kiểu chỉ đến kiểu chuỗi (1).
-2b [access flag] truy xuất của class này.
-2b [this class] tên class, chỉ đến index của một kiểu class (7).
-2b [super] tên class mà class này mở rộng từ, chỉ đến index của kiểu class (7).
-2b [số interface] số implement(thực thi từ) trong class .
- [mảng interface] chứa các tên class thực thi, chỉ đến index của kiểu class(7).
-2b [số field] số các biến trong class.
- [mảng field] chứa các field, mỗi field có cấu trúc:
            .2b: access flag
            .2b: tên  biến, index đến kiểu chuỗi(1)
            .2b: kiểu biến, index đến kiểu chuỗi(1)
            .2b: số thuộc tính
            .[bảng thuộc tính]
-2b [số method] số method trong class
- [mảng method] chứa các method, mỗi method có cấu trúc:
            .2b: access flag
            .2b: tên  method, index đến kiểu chuỗi(1)
            .2b: định nghĩa method, index đến kiểu chuỗi(1)
            .2b: số thuộc tính
            .[bảng thuộc tính]
-2b [số attribute] số thuộc tính trong class
- [mảng attribute] chứa các attribute
            .2b: tên thuộc tính, index đến kiểu chuỗi(1)
            .4b: độ dài thuộc tính a
            .ab [dữ liệu thuộc tính]
Class file thì chỉ có như vậy thôi, tất cả đều được tạo nên từ constant pool và các opcode, phần opcode sẽ nói trong bytecode. Nhất là opcode chỉ sử dụng trong method, cùng với đó là các constant pool kiểu  3, 4, 5, 6, 8, 9, 10, 11. Các giá trị thì lấy từ kiểu 3, 4, 5, 6, 8 còn code thì sử dụng 9, 10 ,11 kết hợp với opcode nữa.
Chú ý một chút:
-       Vì constant pool ở index 0 không được sử dụng, do đó nó luôn là null và cũng không cần phải liệt kê trong mảng constant pool, vì vậy số constant pool được liệt kê trong mảng constant pool luôn ít hơn số constant pool là 1.
-       Đối với constant kiểu long (5) và double (6), thì cứ mỗi khi có một constant kiểu như vậy, constant pool tiếp theo sẽ mang giá trị giống vậy, tức là nó chiếm tới 2 constant pool.
-       Thuộc tính của method có nhiều nhưng trong đó quan trọng nhất là Code và StackMap. Khỏi phải nói thì cũng biết Code là để chứa code, còn StackMap là để veritified class file.
[Code]
2b: tên (1)
4b: độ dài dữ liệu còn lại
2b: max stack
2b: max local
4b: độ dài code a
ab: dữ liệu code
2b: mảng exception {
            .2b: start at
            .2b: end at
            .2b: handler
            .2b: index đến một kiểu exception (1) }
2b: số thuộc tính phụ
[bảng thuộc tính phụ]

[StackMap]
2b: tên (1)
4b: độ dài dữ liệu còn lại
2b: số stack
[mảng stack] {
            .2b: start at (offset frame)
            .2b: số variable
            .[mảng variable] { //bắt đầu 1b chỉ loại, tùy loại mà
                        0: 0b, 1: 0b, 2: 0b, 3: 0b, 4: 0b, 5: 0b, 6: 0b, 7: 2b, 8: 2b }
            .2b: số stack
            .[mảng stack] { //bắt đầu 1b chỉ loại, tùy loại mà
                        0: 0b, 1: 0b, 2: 0b, 3: 0b, 4: 0b, 5: 0b, 6: 0b, 7: 2b, 8: 2b }
OPCODE:
Cũng giống như khi bạn phân tích constant pool vậy thôi, chỉ khác là constant chỉ có tới giá trị 12, ở đây ta có nhiều giá trị hơn cho opcode. Mỗi giá trị ứng với một code và có số byte theo sau khác nhau, theo sau đó có thể là một giá trị lấy trực tiếp hoặc là lấy từ constant pool qua kiểu 3, 4, 5, 6, 8 hoặc là các kiểu code 9, 10, 11. Chỉ cần  đọc là bạn sẽ hiểu. các giá trị được chuyển qua hex cho đồng nhất
32: aaload
53: aastore
01: aconst_null
19: aload ->1b: vị trí load
2a: aload_0
2b: aload_1
2c: aload_2
2d: aload_3
bd: anewarray ->2b: chỉ đến kiểu class
b0: areturn
be: arraylength
3a: astore ->1b:vị trí lưu
4b: astore_0
4c: astore_1
4d: astore_2
4e: astore_3
bf: athrow
33: baload
54: bastore
10: bipush ->1b: giá trị
ca: breakpoint
34: caload
55: castore
c0: checkcast ->2b: chỉ đến kiểu class
90: d2f
8e: d2i
8f: d2l
63: dadd
31: daload
52: dastore
98: dcmpg
97: dcmpl
0e: dconst_0
0f: dconst_1
6f: ddiv
18: dload ->1b: vị trí load
26: dload_0
27: dload_1
28: dload_2
29: dload_3
6b: dmul
77: dneg
73: drem
af: dreturn
39: dstore ->1b: vị trí lưu
47: dstore_0
48: dstore_1
49: dstore_2
4a: dstore_3
67: dsub
59: dup
5a: dup_x1
5b: dup_x2
5c: dup2
5d: dup2_x1
5e: dup2_x2
8d: f2d
8b: f2i
8c: f2l
62: fadd
30: faload
51: fastore
96: fcmpg
95: fcmpl
0b: fconst_0
0c: fconst_1
0d: fconst_2
6e: fdiv
17: fload ->1b: vị trí load
22: fload_0
23: fload_1
24: fload_2
25: fload_3
6a: fmul
76: fneg
72: frem
ae: freturn
38: fstore ->1b: vị trí lưu
43: fstore_0
44: fstore_1
45: fstore_2
46: fstore_3
66: fsub
b4: getfield ->2b: chỉ đến kiểu 9
b2: getstatic ->2b: chỉ đến kiểu 9
a7: goto ->2b: vị trí đi đến
c8: goto_w ->4b: vị trí đi đến
91: i2b
92: i2c
87: i2d
86: i2f
85: i2l
93: i2s
60: iadd
2e: iaload
7e: iand
4f: iastore
03: iconst_0
04: iconst_1
05: iconst_2
06: iconst_3
07: iconst_4
08: iconst_5
02: iconst_m1
6c: idiv
a5: if_acmpeq ->2b: vị trí đi đến
a6: if_acmpne ->2b: vị trí đi đến
9f: if_icmpeq ->2b: vị trí đi đến
a2: if_icmpge ->2b: vị trí đi đến
a3: if_icmpgt ->2b: vị trí đi đến
a4: if_icmple ->2b: vị trí đi đến
a1: if_icmplt ->2b: vị trí đi đến
a0: if_icmpne ->2b: vị trí đi đến
99: ifeq ->2b: vị trí đi đến
9c: ifge ->2b: vị trí đi đến
9d: ifgt ->2b: vị trí đi đến
9e: ifle ->2b: vị trí đi đến
9b: iflt ->2b: vị trí đi đến
9a: ifne ->2b: vị trí đi đến
c7: ifnonnull ->2b: vị trí đi đến
c6: ifnull ->2b: vị trí đi đến
84: iinc ->1b: vị trí load, 1b: chỉ số tăng
15: iload ->1b: vị trí load
1a: iload_0
1b: iload_1
1c: iload_2
1d: iload_3
fe: impdep1
ff: impdep2
68: imul
74: ineg
c1: instanceof ->2b: kiêu class
ba: invokedynamic ->2b: kiêểu 10, 1b: 0, 1b: 0
b9: invokeinterface ->2b: kiêểu 11, 1b: số tham số method+1, 1b: 0
b7: invokespecial ->2b: kiêều 10
b8: invokestatic ->2b: kiêều 11
b6: invokevirtual ->2b: kiêều 12
80: ior
70: irem
ac: ireturn
78: ishl
7a: ishr
36: istore ->1b: vĩ trí lưu
3b: istore_0
3c: istore_1
3d: istore_2
3e: istore_3
64: isub
7c: iushr
82: ixor
a8: jsr ->2b: nhảy qua bao nhieu byte
c9: jsr_w ->4b: nhảy qua bao nhiêu byte
8a: l2d
89: l2f
88: l2i
61: ladd
2f: laload
7f: land
50: lastore
94: lcmp
9: lconst_0
0a: lconst_1
12: ldc ->1b: giá trị constant pool
13: ldc_w ->2b: giá trị constant pool
14: ldc2_w ->2b: giá trị constant pool
6d: ldiv
16: lload ->1b: vị trí load
1e: lload_0
1f: lload_1
20: lload_2
21: lload_3
69: lmul
75: lneg
ab: lookupswitch ->0-3b: đệm chia hết cho 4, 4b: default đi đến, 4b: số trường hợp,[trường hợp]{ 4b: giá trị, 4b: vị trí đi]}
81: lor
71: lrem
ad: lreturn
79: lshl
7b: lshr
37: lstore ->1b: vị trí lưu
3f: lstore_0
40: lstore_1
41: lstore_2
42: lstore_3
65: lsub
7d: lushr
83: lxor
c2: monitorenter
c3: monitorexit
c5: multianewarray ->2b: index class, 1b: số mảng con
bb: new ->2b: index class
bc: newarray ->1b: value
00: nop
57: pop
58: pop2
b5: putfield ->2b: kiêều (9)
b3: putstatic ->2b: kiêểu (9)
a9: ret
b1: return
35: saload
56: sastore
11: sipush ->2b: giá trị
5f: swap
aa: tableswitch ->0-3b: đệm chia hết cho 4, 4b: default, mảng so sánh { 4b: giá trị so sánh, 4: nhảy đến}
c4: wide ->1b: opcode, nếu opcode == iinc thì 4b ngược lại 2b
=================
Ngoài ra còn có:
B kiểu byte
 C kiểu char
 D kiểu double
 F kiểu Float
 I kiểu int
 J kiểu long
S kiểu short
 Z kiểu đúng sai (boolean)
L những kiểu khác thì thêm L này vào, kết thúc là dấu “;” ví dụ La; là load a.class
V đây chính là void trong method đó
[ xác định là một array ví dụ [[I là int[][]
Một số ví dụ:
a([[Iljava/lang/String;D)B là byte[] a(int[][] i1,String i2, double i3)

                        .
           



2 nhận xét:

TuanVA nói...

Hay lắm. Tks 4 share

Holyeyed nói...

đã update, chỉnh lại phần attribute, thuộc tính phụ chỉ tồn tại khi phân tích cụ thể từng loại thuộc tính