ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • android 에 사용되었다는 dalvik vm
    카테고리 없음 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는 아래와 같다.


     - 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
    그리고 각 method 안에는
    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가 있는지 다 뜯어 볼 수 있다.

    댓글

Designed by Tistory.