카테고리 없음
android 에 사용되었다는 dalvik vm
_reply_
2007. 11. 14. 02:41
DalvikVM
google android에서 사용한다는 virtual machine.
android가 java기반 개발 환경이라고는 하지만, 실제로 java vm이 들어 있는게 아니고 DalvikVM이라는 android 전용 virtual machine이 들어 있다. class는 loading시점에 dalvik vm의 byte code로 변환되거나, 준비된 tool을 통해 dalvik vm의 format으로 변환되어 download될 수도 있는 것으로 보인다. jar file과 apk file이 공존하는 것으로 봐서 말이다. 그리고 결정적으로 실제 실행되는 code는 cache라는 이름이 붙은 directory에서 실행이 되는 것으로 보아, jar의 경우 compile(translation)된 class를 caching하는 정책을 사용하는 듯하다.
그런데 이름은.. 너무 촌스럽다. 달빅이 뭐냐 달빅이.. 음냥..
java vm과는 다르게 register 기반의 vm이라고 하는데, stack 기반의 vm과 큰 차이가 있는것으로 보이지만 bytecode 내용을 까보니 실제적으로 그렇게 달라 보이지는 않는다. llvm과 흡사한 instruction set을 가졌으리라고 생각했었는데, architecture는 동일하지만 level이 다르다. llvm은 risc cpu level, dalvik vm은 java vm level...(object management(create/gabage collection)이 위에 있느냐 아래에 있느냐의 차이.. 정도 되겠다) 하긴 요즘들어 llvm도 윗 기능들이 하나 하나 vm 아래로 내려가기 시작하니까.. 조만간 이런 형태가 되지 말란 법도 없긴 하지만 말이다.
일단 core.jar에 있는 class들을 까보니, 누군가의 짐작처럼 apache harmony의 class file들을 가져다 사용하고 있었다. org.apache.harmony package의 class들이 잔뜩 들어 있는 것으로 보아 말이다. core.jar에 대략 3000개의 class가 있는데 그 대표적인 package는 아래와 같다.
눈에 띄는건 위에서 말한 harmony 부분과 bouncycastle(harmony에서도 bouncycastle을 썼었는지 기억은 안나지만) 그리고 xmlpull parser를 지원한다는것 정도 되겠다.
다음으로 대표적인 class인 java.lang.Object class의 byte code 내용을 까보면,
와 같다. 외곽 구조는
name, type, access, code, register갯수, argument 갯수, return 갯수등의 정보가 들어 있다.
정도로 java byte code의 format과 거의 비슷한 것으로 보인다. 거의 유일하게 차이나는 것이 instruction set인데, 은근히 비슷하면서도 꽤 다르다. java vm의 byte code instruction을 참고하긴 했으나, 베끼지는 않았다는 흔적이 남아 있는 듯하다. byte code는 stack->register로 피해가고, java class는 haromny를 통해 apache의 등에 숨고.. 나름 상당히 고민한 흔적이 있다. SUN과의 충돌도 피하기 힘들 듯 하다.
다음 리스트는 core.jar에 사용된 instruction의 list이다. 앞의 + prefix(의미는 모르겠다)나, 뒤의 /range, /2addr /lit8, /lit16, /4, /8, /16, /32, /from16, 등의 qualifier를 제외한 리스트이다. (143개)
시간날때 천천히 살펴보면 어떻게 생겨먹었는지 짐작이 갈 듯 하다.
google android에서 사용한다는 virtual machine.
android가 java기반 개발 환경이라고는 하지만, 실제로 java vm이 들어 있는게 아니고 DalvikVM이라는 android 전용 virtual machine이 들어 있다. class는 loading시점에 dalvik vm의 byte code로 변환되거나, 준비된 tool을 통해 dalvik vm의 format으로 변환되어 download될 수도 있는 것으로 보인다. jar file과 apk file이 공존하는 것으로 봐서 말이다. 그리고 결정적으로 실제 실행되는 code는 cache라는 이름이 붙은 directory에서 실행이 되는 것으로 보아, jar의 경우 compile(translation)된 class를 caching하는 정책을 사용하는 듯하다.
그런데 이름은.. 너무 촌스럽다. 달빅이 뭐냐 달빅이.. 음냥..
java vm과는 다르게 register 기반의 vm이라고 하는데, stack 기반의 vm과 큰 차이가 있는것으로 보이지만 bytecode 내용을 까보니 실제적으로 그렇게 달라 보이지는 않는다. llvm과 흡사한 instruction set을 가졌으리라고 생각했었는데, architecture는 동일하지만 level이 다르다. llvm은 risc cpu level, dalvik vm은 java vm level...(object management(create/gabage collection)이 위에 있느냐 아래에 있느냐의 차이.. 정도 되겠다) 하긴 요즘들어 llvm도 윗 기능들이 하나 하나 vm 아래로 내려가기 시작하니까.. 조만간 이런 형태가 되지 말란 법도 없긴 하지만 말이다.
일단 core.jar에 있는 class들을 까보니, 누군가의 짐작처럼 apache harmony의 class file들을 가져다 사용하고 있었다. org.apache.harmony package의 class들이 잔뜩 들어 있는 것으로 보아 말이다. core.jar에 대략 3000개의 class가 있는데 그 대표적인 package는 아래와 같다.
- SQLite - android.access - android.app - android.dalvik - android.net - android.os - android.security - android.xml - com.ibm.icu4jni - java.io - java.lang - java.math - java.net - java.nio - java.security - java.sql - java.text - java.util - javax.crypto - javax.net - javax.security - javax.sound - javax.sql - javax.xml - junit. - org.apache.commons - org.apache.harmony - org.bouncycastle - org.json - org.kxml2 - org.w3c.dom - org.xml.sax - org.xmlpull - sun.misc.Unsafe정도 된다.
눈에 띄는건 위에서 말한 harmony 부분과 bouncycastle(harmony에서도 bouncycastle을 썼었는지 기억은 안나지만) 그리고 xmlpull parser를 지원한다는것 정도 되겠다.
다음으로 대표적인 class인 java.lang.Object class의 byte code 내용을 까보면,
Class #281 - Class name : 'java/lang/Object' Access flags : 0x20001 (PUBLIC OPTIMIZED) Interfaces - Static fields - Instance fields - Direct methods - #0 : (in java/lang/Object) name : '' type : '()V' access : 0x0001 (PUBLIC) code - registers : 2 ins : 1 outs : 0 source_idx : 21099 insns : 1 16-bit code units 434ebc: |[434ebc] java/lang/Object. :()V 434ec0: 0e00 |0000: return-void exceptions : (none) positions : 1 0x0000 line=32 locals : 1 0x0000 - 0x0001 reg=1 this Ljava/lang/Object; #1 : (in java/lang/Object) name : 'internalClone' type : '(Ljava/lang/Cloneable;)Ljava/lang/Object;' access : 0x0102 (PRIVATE NATIVE) code : (none) Virtual methods - #0 : (in java/lang/Object) name : 'clone' type : '()Ljava/lang/Object;' access : 0x0004 (PROTECTED) code - registers : 4 ins : 1 outs : 2 source_idx : 21099 insns : 21 16-bit code units 434ec4: |[434ec4] java/lang/Object.clone:()Ljava/lang/Object; 434ec8: 1f31 ac04 |0000: instance-of v1, v3, java/lang/Cloneable // class@04ac 434ecc: 3e01 0a00 |0002: if-nez v1, 000c // +000a 434ed0: 2101 6102 |0004: new-instance v1, java/lang/CloneNotSupportedException // class@0261 434ed4: 1802 1d0b |0006: const-string v2, "Class doesn't implement Cloneable" // string@0b1d 434ed8: 6f02 840c 2100 |0008: invoke-direct {v1, v2}, java/lang/CloneNotSupportedException. :(Ljava/lang/ String;)V // method@0c84 434ede: 3201 |000b: throw v1 434ee0: 0730 |000c: move-object v0, v3 434ee2: 1e00 ac04 |000d: check-cast v0, java/lang/Cloneable // class@04ac 434ee6: 0701 |000f: move-object v1, v0 434ee8: 6f02 bc0d 1300 |0010: invoke-direct {v3, v1}, java/lang/Object.internalClone:(Ljava/lang/Cloneable;)Lj ava/lang/Object; // method@0dbc 434eee: 0c01 |0013: move-result-object v1 434ef0: 1101 |0014: return-object v1 exceptions : (none) positions : 3 0x0000 line=46 0x0004 line=47 0x000c line=50 locals : 1 0x0000 - 0x0015 reg=3 this Ljava/lang/Object; #1 : (in java/lang/Object) name : 'equals' type : '(Ljava/lang/Object;)Z' access : 0x0001 (PUBLIC) code - registers : 3 ins : 2 outs : 0 source_idx : 21099 insns : 6 16-bit code units 434ef4: |[434ef4] java/lang/Object.equals:(Ljava/lang/Object;)Z 434ef8: 3821 0400 |0000: if-ne v1, v2, 0004 // +0004 434efc: 1210 |0002: const/4 v0, #int 1 // #1 434efe: 0f00 |0003: return v0 434f00: 1200 |0004: const/4 v0, #int 0 // #0 434f02: 33fe |0005: goto 0003 // -0002 exceptions : (none) positions : 1 0x0000 line=70 locals : 2 0x0000 - 0x0006 reg=1 this Ljava/lang/Object; 0x0000 - 0x0006 reg=2 o Ljava/lang/Object; #2 : (in java/lang/Object) name : 'finalize' type : '()V' access : 0x0004 (PROTECTED) code - registers : 2 ins : 1 outs : 0 source_idx : 21099 insns : 1 16-bit code units 434f04: |[434f04] java/lang/Object.finalize:()V 434f08: 0e00 |0000: return-void exceptions : (none) positions : 1 0x0000 line=88 locals : 1 0x0000 - 0x0001 reg=1 this Ljava/lang/Object; #3 : (in java/lang/Object) name : 'getClass' type : '()Ljava/lang/Class;' access : 0x0111 (PUBLIC FINAL NATIVE) code : (none) #4 : (in java/lang/Object) name : 'hashCode' type : '()I' access : 0x0101 (PUBLIC NATIVE) code : (none) #5 : (in java/lang/Object) name : 'notify' type : '()V' access : 0x0111 (PUBLIC FINAL NATIVE) code : (none) #6 : (in java/lang/Object) name : 'notifyAll' type : '()V' access : 0x0111 (PUBLIC FINAL NATIVE) code : (none) #7 : (in java/lang/Object) name : 'toString' type : '()Ljava/lang/String;' access : 0x0001 (PUBLIC) code - registers : 3 ins : 1 outs : 2 source_idx : 21099 insns : 40 16-bit code units 434f0c: |[434f0c] java/lang/Object.toString:()Ljava/lang/String; 434f10: 2100 b407 |0000: new-instance v0, java/lang/StringBuilder // class@07b4 434f14: 6f01 540f 0000 |0002: invoke-direct {v0}, java/lang/StringBuilder. :()V // method@0f54 434f1a: f801 0300 0200 |0005: +invoke-virtual-quick {v2}, [0003] // vtable #0003 434f20: 0c01 |0008: move-result-object v1 434f22: f801 2900 0100 |0009: +invoke-virtual-quick {v1}, [0029] // vtable #0029 434f28: 0c01 |000c: move-result-object v1 434f2a: f802 3700 1000 |000d: +invoke-virtual-quick {v0, v1}, [0037] // vtable #0037 434f30: 0c00 |0010: move-result-object v0 434f32: 1301 4000 |0011: const/16 v1, #int 64 // #40 434f36: f802 3100 1000 |0013: +invoke-virtual-quick {v0, v1}, [0031] // vtable #0031 434f3c: 0c00 |0016: move-result-object v0 434f3e: f801 0400 0200 |0017: +invoke-virtual-quick {v2}, [0004] // vtable #0004 434f44: 0a01 |001a: move-result v1 434f46: 7001 2f0d 0100 |001b: invoke-static {v1}, java/lang/Integer.toHexString:(I)Ljava/lang/String; // method@0d2f 434f4c: 0c01 |001e: move-result-object v1 434f4e: f802 3700 1000 |001f: +invoke-virtual-quick {v0, v1}, [0037] // vtable #0037 434f54: 0c00 |0022: move-result-object v0 434f56: f801 0700 0000 |0023: +invoke-virtual-quick {v0}, [0007] // vtable #0007 434f5c: 0c00 |0026: move-result-object v0 434f5e: 1100 |0027: return-object v0 exceptions : (none) positions : 1 0x0000 line=145 locals : 1 0x0000 - 0x0028 reg=2 this Ljava/lang/Object; #8 : (in java/lang/Object) name : 'wait' type : '()V' access : 0x0011 (PUBLIC FINAL) code - registers : 4 ins : 1 outs : 4 source_idx : 21099 insns : 7 16-bit code units 434f60: |[434f60] java/lang/Object.wait:()V 434f64: 1500 0000 |0000: const-wide/16 v0, #int 0 // #0 434f68: 1202 |0002: const/4 v2, #int 0 // #0 434f6a: f804 0a00 0321 |0003: +invoke-virtual-quick {v3, v0, v1, v2}, [000a] // vtable #000a 434f70: 0e00 |0006: return-void exceptions : (none) positions : 2 0x0000 line=170 0x0006 line=171 locals : 1 0x0000 - 0x0007 reg=3 this Ljava/lang/Object; #9 : (in java/lang/Object) name : 'wait' type : '(J)V' access : 0x0011 (PUBLIC FINAL) code - registers : 4 ins : 3 outs : 4 source_idx : 21099 insns : 5 16-bit code units 434f74: |[434f74] java/lang/Object.wait:(J)V 434f78: 1200 |0000: const/4 v0, #int 0 // #0 434f7a: f804 0a00 2103 |0001: +invoke-virtual-quick {v1, v2, v3, v0}, [000a] // vtable #000a 434f80: 0e00 |0004: return-void exceptions : (none) positions : 2 0x0000 line=195 0x0004 line=196 locals : 2 0x0000 - 0x0005 reg=1 this Ljava/lang/Object; 0x0000 - 0x0005 reg=2 time J #10 : (in java/lang/Object) name : 'wait' type : '(JI)V' access : 0x0111 (PUBLIC FINAL NATIVE) code : (none)
와 같다. 외곽 구조는
- Class name
- Access flag
- Interface list
- Static fields
- Instance fields
- Direct methods
- Virtual methods
name, type, access, code, register갯수, argument 갯수, return 갯수등의 정보가 들어 있다.
정도로 java byte code의 format과 거의 비슷한 것으로 보인다. 거의 유일하게 차이나는 것이 instruction set인데, 은근히 비슷하면서도 꽤 다르다. java vm의 byte code instruction을 참고하긴 했으나, 베끼지는 않았다는 흔적이 남아 있는 듯하다. byte code는 stack->register로 피해가고, java class는 haromny를 통해 apache의 등에 숨고.. 나름 상당히 고민한 흔적이 있다. SUN과의 충돌도 피하기 힘들 듯 하다.
다음 리스트는 core.jar에 사용된 instruction의 list이다. 앞의 + prefix(의미는 모르겠다)나, 뒤의 /range, /2addr /lit8, /lit16, /4, /8, /16, /32, /from16, 등의 qualifier를 제외한 리스트이다. (143개)
시간날때 천천히 살펴보면 어떻게 생겨먹었는지 짐작이 갈 듯 하다.
add-double add-float add-int add-long aget aget-boolean aget-byte aget-char aget-object aget-short aget-wide and-int and-long aput aput-boolean aput-byte aput-char aput-object aput-short aput-wide array-length check-cast cmp-long cmpg-double cmpg-float cmpl-double cmpl-float const const-class const-string const-wide div-double div-float div-int div-long double-to-float double-to-int double-to-long execute-inline filled-new-array float-to-double float-to-int float-to-long goto if-eq if-eqz if-ge if-gez if-gt if-gtz if-le if-lez if-lt if-ltz if-ne if-nez iget-object-quick iget-quick iget-wide-quick instance-of int-to-byte int-to-char int-to-double int-to-float int-to-long int-to-short invoke-direct invoke-direct-empty invoke-interface invoke-static invoke-super-quick invoke-virtual-quick iput-object-quick iput-quick iput-wide-quick long-to-double long-to-float long-to-int monitor-enter monitor-exit move move-exception move-object move-result move-result-object move-result-wide move-wide mul-double mul-float mul-int mul-long neg-double neg-float neg-int neg-long new-array new-array-boolean new-array-byte new-array-char new-array-double new-array-float new-array-int new-array-long new-array-short new-instance nop or-int or-long packed-switch packed-switch-data rem-int rem-long return return-object return-void return-wide sget sget-boolean sget-byte sget-char sget-object sget-wide shl-int shl-long shr-int shr-long sparse-switch sparse-switch-data sput sput-boolean sput-byte sput-char sput-object sput-wide sub-double sub-float sub-int sub-long throw ushr-int ushr-long xor-int xor-long좀더 자세한 내용을 원한다면, emulator를 띄우면서 -C option을 주면 console prompt가 떨어지므로 거기에서 dexdump command를 이용해 dex file을 dump해 볼 수 있다. dumper를 통해 본 내용이므로 정확한 binary format을 알 수는 없지만 대략 어떤 종류의 정보가 있으며, 어떤 class/method가 있는지 다 뜯어 볼 수 있다.