ART世界探险(6) - 流程控制指令

来源:互联网 发布:如何查询淘宝买家等级 编辑:程序博客网 时间:2024/04/30 01:06

ART世界探险(6) - 流程控制指令

分支结构

Java分支结构

我们先来个最简单的,比较大小吧。

    public static long bigger(long a, long b){        if(a>=b){            return a;        }else{            return b;        }    }    public static int less(int a,int b){        if(a<=b){            return a;        }else{            return b;        }    }

看看Java字节码是个什么样子:

  public static long bigger(long, long);    Code:       0: lload_0       1: lload_2       2: lcmp       3: iflt          8       6: lload_0       7: lreturn       8: lload_2       9: lreturn  public static int less(int, int);    Code:       0: iload_0       1: iload_1       2: if_icmpgt     7       5: iload_0       6: ireturn       7: iload_1       8: ireturn

lcmp是两个长整型做比较,结果影响标志位。然后iflt判断是否是小于(lt=less than),如果是则跳到8 ,不是则继续往下走。

普通整型的判断和比较在同一条指令里,if_icmpgt是判大于(gt=greater than),如果大于则跳转到7。

ARM的分支结构

对于这种根据不同情况选择不同值的语句,ARM在设计时专门有一条强大的csel指令,专门做这个事情。
先用cmp指令比较两个值,然后设置条件,ge是大于或等于,le是小于或等于。如果条件满足,则x0就是x0,否则x0取x1的值。

000000000000079c <_Z6biggerll>: 79c:   eb01001f    cmp x0, x1 7a0:   9a81a000    csel    x0, x0, x1, ge 7a4:   d65f03c0    ret00000000000007a8 <_Z4lessii>: 7a8:   6b01001f    cmp w0, w1 7ac:   1a81d000    csel    w0, w0, w1, le 7b0:   d65f03c0    ret

Thumb2指令的分支结构

csel这样的指令需要32位的长度才放得下. Thumb2本着能省则省的原则,改用16位的条件mov指令来实现,可以节省2个字节指令空间。

0000101c <_Z6biggerll>:    101c:   4288        cmp r0, r1    101e:   bfb8        it  lt    1020:   4608        movlt   r0, r1    1022:   4770        bx  lr00001024 <_Z4lessii>:    1024:   4288        cmp r0, r1    1026:   bfa8        it  ge    1028:   4608        movge   r0, r1    102a:   4770        bx  lr

Thumb指令的分支结构

Thumb指令没有带条件的mov操作,更不可能有csel这样复杂的指令了。那也没问题,返璞归真,我们直接跳转就是了呗〜
bge.n,是说大于或等于,也就是不小于的时候直接跳到12aa,就是bx lr返回这条指令上去。

adds r0, r1, #0其实也可以翻译成movs r0,r1。前面我们讲过,movs r0,r1其实是adds r0, r1, #0的别名。本质上是一回事。

000012a4 <_Z6biggerll>:    12a4:   4288        cmp r0, r1    12a6:   da00        bge.n   12aa <_Z6biggerll+0x6>    12a8:   1c08        adds    r0, r1, #0    12aa:   4770        bx  lr000012ac <_Z4lessii>:    12ac:   4288        cmp r0, r1    12ae:   dd00        ble.n   12b2 <_Z4lessii+0x6>    12b0:   1c08        adds    r0, r1, #0    12b2:   4770        bx  lr

x86_64的分支结构

x86_64中也是有带有条件的赋值指令的。

0000000000000740 <_Z6biggerll>: 740:   48 39 f7                cmp    %rsi,%rdi 743:   48 89 f0                mov    %rsi,%rax 746:   48 0f 4d c7             cmovge %rdi,%rax 74a:   c3                      retq    74b:   0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)0000000000000750 <_Z4lessii>: 750:   39 f7                   cmp    %esi,%edi 752:   89 f0                   mov    %esi,%eax 754:   0f 4e c7                cmovle %edi,%eax 757:   c3                      retq    758:   0f 1f 84 00 00 00 00    nopl   0x0(%rax,%rax,1) 75f:   00 

x86的分支结构

cmov在x86上也是有的。

00000630 <_Z6biggerll>: 630:   8b 44 24 04             mov    0x4(%esp),%eax 634:   8b 54 24 08             mov    0x8(%esp),%edx 638:   39 d0                   cmp    %edx,%eax 63a:   0f 4c c2                cmovl  %edx,%eax 63d:   c3                      ret     63e:   66 90                   xchg   %ax,%ax00000640 <_Z4lessii>: 640:   8b 44 24 04             mov    0x4(%esp),%eax 644:   8b 54 24 08             mov    0x8(%esp),%edx 648:   39 d0                   cmp    %edx,%eax 64a:   0f 4f c2                cmovg  %edx,%eax 64d:   c3                      ret     64e:   66 90                   xchg   %ax,%ax

mips64的分支结构

感觉上罗嗦了一点,但是本质上跟csel是一样的。

0000000000000c00 <_Z6biggerll>: c00:   0085182a    slt v1,a0,a1 c04:   00832035    seleqz  a0,a0,v1 c08:   00a31037    selnez  v0,a1,v1 c0c:   03e00009    jr  ra c10:   00821025    or  v0,a0,v0 c14:   00000000    nop0000000000000c18 <_Z4lessii>: c18:   00a4102a    slt v0,a1,a0 c1c:   00a22837    selnez  a1,a1,v0 c20:   00822035    seleqz  a0,a0,v0 c24:   03e00009    jr  ra c28:   00a41025    or  v0,a1,a0 c2c:   00000000    nop

mips的分支结构:

比起上面64位的,是不是感觉更加清爽呢?

00000710 <_Z6biggerll>: 710:   0085102a    slt v0,a0,a1 714:   0082280a    movz    a1,a0,v0 718:   03e00008    jr  ra 71c:   00a01021    move    v0,a100000720 <_Z4lessii>: 720:   00a4102a    slt v0,a1,a0 724:   0082280a    movz    a1,a0,v0 728:   03e00008    jr  ra 72c:   00a01021    move    v0,a1

分支结构生成的OAT

我们先看生成的Dalvik代码:

  2: long com.yunos.xulun.testcppjni2.TestART.bigger(long, long) (dex_method_idx=16779)    DEX CODE:      0x0000: 3100 0204                 | cmp-long v0, v2, v4      0x0002: 3a00 0300                 | if-ltz v0, +3      0x0004: 1002                      | return-wide v2      0x0005: 0442                      | move-wide v2, v4      0x0006: 28fe                      | goto -2

看起来稍微有点绕,不过总体上还算是清晰。

    CODE: (code_offset=0x0050277c size_offset=0x00502778 size=116)...      0x0050277c: d1400bf0  sub x16, sp, #0x2000 (8192)      0x00502780: b940021f  ldr wzr, [x16]      suspend point dex PC: 0x0000      0x00502784: f81e0fe0  str x0, [sp, #-32]!      0x00502788: f9000ffe  str lr, [sp, #24]      0x0050278c: f90017e1  str x1, [sp, #40]      0x00502790: f9001be2  str x2, [sp, #48]      0x00502794: 79400250  ldrh w16, [tr] (state_and_flags)      0x00502798: 35000270  cbnz w16, #+0x4c (addr 0x5027e4)

两个参数在上面分别存到了sp+40和sp+48中,现在再读回到x0和x1中。
用cmp指令来比较。
下面用到条件设置的cset指令,这是一条将flag转成1或0的值的指令。这条指令是cinc指令的一个别名。
如果是NE,就将w2设置成1,否则就设成0.

      0x0050279c: f94017e0  ldr x0, [sp, #40]      0x005027a0: f9401be1  ldr x1, [sp, #48]      0x005027a4: eb01001f  cmp x0, x1      0x005027a8: 1a9f07e2  cset w2, ne

下面再来一条cneg,条件取负,如果lt的话,就将-w2赋给w2,否则就将w2赋给w2.
这个结果先暂存到栈里,再读到w0,去做下一次比较。
如果刚才这个条件取负的值大于0,则w1赋给w0.
根所cset的结果,来决定cbnz是不是要跳转,就是要不要将第二个参数sp+48的值换到sp+40的位置。
最后返回sp+40处变量的值。

      0x005027ac: 5a82a442  cneg w2, w2, lt      0x005027b0: b9000fe2  str w2, [sp, #12]      0x005027b4: b9400fe0  ldr w0, [sp, #12]      0x005027b8: 7100001f  cmp w0, #0x0 (0)      0x005027bc: 1a9fa7e1  cset w1, lt      0x005027c0: 2a0103e0  mov w0, w1      0x005027c4: 350000a0  cbnz w0, #+0x14 (addr 0x5027d8)      0x005027c8: f94017e0  ldr x0, [sp, #40]      0x005027cc: f9400ffe  ldr lr, [sp, #24]      0x005027d0: 910083ff  add sp, sp, #0x20 (32)      0x005027d4: d65f03c0  ret      0x005027d8: fd401bff  ldr d31, [sp, #48]      0x005027dc: fd0017ff  str d31, [sp, #40]      0x005027e0: 17fffffa  b #-0x18 (addr 0x5027c8)      0x005027e4: f9421e5e  ldr lr, [tr, #1080] (pTestSuspend)      0x005027e8: d63f03c0  blr lr      suspend point dex PC: 0x0000      0x005027ec: 17ffffec  b #-0x50 (addr 0x50279c)

循环结构

我们写一个while循环,一个do while循环和一个for循环来测试一下,其实本质上差不多是一回事情:

    public static long testWhile(int value){        int i=0;        long sum = 0;        while(i<=value){            sum += i;            i++;        }        return sum;    }    public static long testDoWhile(int value){        long sum = 0;        int i=0;        do{            sum += i;            i++;        }while(i<value);        return sum;    }    public static long testFor(int value){        long sum = 0;        for(int i=0;i<=value;i++){            sum += i;        }        return sum;    }

Java字节码的循环结构

我们先来解释其中第一个吧。这其中唯一遇到的新指令是无条件跳转的goto指令。
其中第6标号的if_icmpgt我们在分支中学过了。

  public static long testWhile(int);    Code:       0: iconst_0       1: istore_1       2: lconst_0       3: lstore_2       4: iload_1       5: iload_0       6: if_icmpgt     20       9: lload_2      10: iload_1      11: i2l      12: ladd      13: lstore_2      14: iinc          1, 1      17: goto          4      20: lload_2      21: lreturn

后面两个与上面的非常类似。只是指令顺序上稍有不同而己。

  public static long testDoWhile(int);    Code:       0: lconst_0       1: lstore_1       2: iconst_0       3: istore_3       4: lload_1       5: iload_3       6: i2l       7: ladd       8: lstore_1       9: iinc          3, 1      12: iload_3      13: iload_0      14: if_icmplt     4      17: lload_1      18: lreturn  public static long testFor(int);    Code:       0: lconst_0       1: lstore_1       2: iconst_0       3: istore_3       4: iload_3       5: iload_0       6: if_icmpgt     20       9: lload_1      10: iload_3      11: i2l      12: ladd      13: lstore_1      14: iinc          3, 1      17: goto          4      20: lload_1      21: lreturn

Thumb的循环结构

C++代码与Java代码几乎是一字未改:

long testWhile(int value){    int i=0;    long sum = 0;    while(i<=value){        sum += i;        i++;    }    return sum;}long testDoWhile(int value){    long sum = 0;    int i=0;    do{        sum += i;        i++;    }while(i<value);    return sum;}long testFor(int value){    long sum = 0;    for(int i=0;i<=value;i++){        sum += i;    }    return sum;}

我们下面来看看16位的Thumb指令是如何实现循环的。
value参数传进来在r0。将r2,r3清0, r2与参数传进来的r0比较,如果0已经比r0大了,循环结束,将结果r3赋给r0,返回。
如果0比r0小,则继续循环,r3结果等于r3值加上r2值,r2值随后加1。然后无条件回12b8那条比较语句,再判断r2是不是大于r0,如此循环。

000012b4 <_Z9testWhilei>:    12b4:   2300        movs    r3, #0    12b6:   1c1a        adds    r2, r3, #0    12b8:   4282        cmp r2, r0    12ba:   dc02        bgt.n   12c2 <_Z9testWhilei+0xe>    12bc:   189b        adds    r3, r3, r2    12be:   3201        adds    r2, #1    12c0:   e7fa        b.n 12b8 <_Z9testWhilei+0x4>    12c2:   1c18        adds    r0, r3, #0    12c4:   4770        bx  lr

后面两个也是语句位置变了变,本质是一样的。

000012c6 <_Z11testDoWhilei>:    12c6:   2300        movs    r3, #0    12c8:   1c1a        adds    r2, r3, #0    12ca:   18d2        adds    r2, r2, r3    12cc:   3301        adds    r3, #1    12ce:   4283        cmp r3, r0    12d0:   dbfb        blt.n   12ca <_Z11testDoWhilei+0x4>    12d2:   1c10        adds    r0, r2, #0    12d4:   4770        bx  lr000012d6 <_Z7testFori>:    12d6:   2300        movs    r3, #0    12d8:   1c1a        adds    r2, r3, #0    12da:   4283        cmp r3, r0    12dc:   dc02        bgt.n   12e4 <_Z7testFori+0xe>    12de:   18d2        adds    r2, r2, r3    12e0:   3301        adds    r3, #1    12e2:   e7fa        b.n 12da <_Z7testFori+0x4>    12e4:   1c10        adds    r0, r2, #0    12e6:   4770        bx  lr

Thumb2的循环结构

v7a的循环结构

我们只看一个吧,除了地址不同,与前面的Thumb指令完全相同,所以略过不讲了。

0000102c <_Z9testWhilei>:    102c:   2300        movs    r3, #0    102e:   461a        mov r2, r3    1030:   4282        cmp r2, r0    1032:   dc02        bgt.n   103a <_Z9testWhilei+0xe>    1034:   4413        add r3, r2    1036:   3201        adds    r2, #1    1038:   e7fa        b.n 1030 <_Z9testWhilei+0x4>    103a:   4618        mov r0, r3    103c:   4770        bx  lr

mips的循环结构

我们再看下mips的三个循环结构,也跟上面所讲的差不多。

00000730 <_Z9testWhilei>: 730:   04800009    bltz    a0,758 <_Z9testWhilei+0x28> 734:   24840001    addiu   a0,a0,1 738:   00001021    move    v0,zero 73c:   00001821    move    v1,zero 740:   00431021    addu    v0,v0,v1 744:   24630001    addiu   v1,v1,1 748:   1464fffe    bne v1,a0,744 <_Z9testWhilei+0x14> 74c:   00431021    addu    v0,v0,v1 750:   03e00008    jr  ra 754:   00431023    subu    v0,v0,v1 758:   03e00008    jr  ra 75c:   00001021    move    v0,zero00000760 <_Z11testDoWhilei>: 760:   00001821    move    v1,zero 764:   00001021    move    v0,zero 768:   00431021    addu    v0,v0,v1 76c:   24630001    addiu   v1,v1,1 770:   0064282a    slt a1,v1,a0 774:   14a0fffd    bnez    a1,76c <_Z11testDoWhilei+0xc> 778:   00431021    addu    v0,v0,v1 77c:   03e00008    jr  ra 780:   00431023    subu    v0,v0,v100000784 <_Z7testFori>: 784:   04800009    bltz    a0,7ac <_Z7testFori+0x28> 788:   24840001    addiu   a0,a0,1 78c:   00001821    move    v1,zero 790:   00001021    move    v0,zero 794:   00431021    addu    v0,v0,v1 798:   24630001    addiu   v1,v1,1 79c:   1464fffe    bne v1,a0,798 <_Z7testFori+0x14> 7a0:   00431021    addu    v0,v0,v1 7a4:   03e00008    jr  ra 7a8:   00431023    subu    v0,v0,v1 7ac:   03e00008    jr  ra 7b0:   00001021    move    v0,zero

mips64的循环结构

64位的除了加减法换成支持64位的了,其它没有变化。

0000000000000c30 <_Z9testWhilei>: c30:   0480000a    bltz    a0,c5c <_Z9testWhilei+0x2c> c34:   64840001    daddiu  a0,a0,1 c38:   0000182d    move    v1,zero c3c:   0000102d    move    v0,zero c40:   0043102d    daddu   v0,v0,v1 c44:   00000000    nop c48:   64630001    daddiu  v1,v1,1 c4c:   1464fffe    bne v1,a0,c48 <_Z9testWhilei+0x18> c50:   0043102d    daddu   v0,v0,v1 c54:   03e00009    jr  ra c58:   0043102f    dsubu   v0,v0,v1 c5c:   03e00009    jr  ra c60:   0000102d    move    v0,zero c64:   00000000    nop0000000000000c68 <_Z11testDoWhilei>: c68:   0000182d    move    v1,zero c6c:   0000102d    move    v0,zero c70:   0043102d    daddu   v0,v0,v1 c74:   64630001    daddiu  v1,v1,1 c78:   00032800    sll a1,v1,0x0 c7c:   5ca4fffc    bltc    a1,a0,c70 <_Z11testDoWhilei+0x8> c80:   00000000    nop c84:   d81f0000    jrc ra0000000000000c88 <_Z7testFori>: c88:   0480000a    bltz    a0,cb4 <_Z7testFori+0x2c> c8c:   64840001    daddiu  a0,a0,1 c90:   0000182d    move    v1,zero c94:   0000102d    move    v0,zero c98:   0043102d    daddu   v0,v0,v1 c9c:   00000000    nop ca0:   64630001    daddiu  v1,v1,1 ca4:   1464fffe    bne v1,a0,ca0 <_Z7testFori+0x18> ca8:   0043102d    daddu   v0,v0,v1 cac:   03e00009    jr  ra cb0:   0043102f    dsubu   v0,v0,v1 cb4:   03e00009    jr  ra cb8:   0000102d    move    v0,zero cbc:   00000000    nop

arm v8a的循环结构

下面我们看第一个while循环在v8a上的实现:
竟然动用了强大的NEON指令!

00000000000007c0 <_Z9testWhilei>: 7c0:   2a0003e3    mov w3, w0 7c4:   37f80643    tbnz    w3, #31, 88c <_Z9testWhilei+0xcc> 7c8:   51000c60    sub w0, w3, #0x3 7cc:   7100147f    cmp w3, #0x5 7d0:   53027c00    lsr w0, w0, #2 7d4:   11000464    add w4, w3, #0x1 7d8:   11000400    add w0, w0, #0x1 7dc:   531e7402    lsl w2, w0, #2 7e0:   5400050d    b.le    880 <_Z9testWhilei+0xc0> 7e4:   100005e5    adr x5, 8a0 <_Z9testWhilei+0xe0> 7e8:   4f000484    movi    v4.4s, #0x4 7ec:   4f000400    movi    v0.4s, #0x0 7f0:   52800001    mov w1, #0x0                    // #0 7f4:   3dc000a1    ldr q1, [x5] 7f8:   0f20a422    sxtl    v2.2d, v1.2s 7fc:   11000421    add w1, w1, #0x1 800:   4f20a423    sxtl2   v3.2d, v1.4s 804:   6b01001f    cmp w0, w1 808:   4ea48421    add v1.4s, v1.4s, v4.4s 80c:   4ee08440    add v0.2d, v2.2d, v0.2d 810:   4ee08460    add v0.2d, v3.2d, v0.2d 814:   54ffff28    b.hi    7f8 <_Z9testWhilei+0x38> 818:   5ef1b800    addp    d0, v0.2d 81c:   6b02009f    cmp w4, w2 820:   4e083c00    mov x0, v0.d[0] 824:   540002c0    b.eq    87c <_Z9testWhilei+0xbc> 828:   11000444    add w4, w2, #0x1 82c:   8b22c000    add x0, x0, w2, sxtw 830:   6b04007f    cmp w3, w4 834:   5400024b    b.lt    87c <_Z9testWhilei+0xbc> 838:   11000841    add w1, w2, #0x2 83c:   8b24c000    add x0, x0, w4, sxtw 840:   6b01007f    cmp w3, w1 844:   540001cb    b.lt    87c <_Z9testWhilei+0xbc> 848:   11000c44    add w4, w2, #0x3 84c:   8b21c000    add x0, x0, w1, sxtw 850:   6b04007f    cmp w3, w4 854:   5400014b    b.lt    87c <_Z9testWhilei+0xbc> 858:   11001041    add w1, w2, #0x4 85c:   8b24c000    add x0, x0, w4, sxtw 860:   6b01007f    cmp w3, w1 864:   540000cb    b.lt    87c <_Z9testWhilei+0xbc> 868:   11001442    add w2, w2, #0x5 86c:   8b21c000    add x0, x0, w1, sxtw 870:   6b02007f    cmp w3, w2 874:   8b22c001    add x1, x0, w2, sxtw 878:   9a80a020    csel    x0, x1, x0, ge 87c:   d65f03c0    ret 880:   d2800000    mov x0, #0x0                    // #0 884:   52800002    mov w2, #0x0                    // #0 888:   17ffffe8    b   828 <_Z9testWhilei+0x68> 88c:   d2800000    mov x0, #0x0                    // #0 890:   d65f03c0    ret 894:   d503201f    nop 898:   d503201f    nop 89c:   d503201f    nop 8a0:   00000000    .inst   0x00000000 ; undefined 8a4:   00000001    .inst   0x00000001 ; undefined 8a8:   00000002    .inst   0x00000002 ; undefined 8ac:   00000003    .inst   0x00000003 ; undefined

篇幅所限,另两个就不列举了。

x86_64的循环结构

x86不甘人后,也动用了MMX整数的SIMD指令来完成这个小循环。。。

0000000000000760 <_Z9testWhilei>: 760:   85 ff                   test   %edi,%edi 762:   0f 88 48 01 00 00       js     8b0 <_Z9testWhilei+0x150> 768:   8d 47 fd                lea    -0x3(%rdi),%eax 76b:   8d 77 01                lea    0x1(%rdi),%esi 76e:   c1 e8 02                shr    $0x2,%eax 771:   83 c0 01                add    $0x1,%eax 774:   83 ff 0e                cmp    $0xe,%edi 777:   8d 14 85 00 00 00 00    lea    0x0(,%rax,4),%edx 77e:   0f 8e 4c 01 00 00       jle    8d0 <_Z9testWhilei+0x170> 784:   66 0f 6f 1d 34 05 00    movdqa 0x534(%rip),%xmm3        # cc0 <Java_xulun_testcppjni2_TestJniCpp_test+0x30> 78b:   00  78c:   31 c9                   xor    %ecx,%ecx 78e:   66 0f 6f 0d 1a 05 00    movdqa 0x51a(%rip),%xmm1        # cb0 <Java_xulun_testcppjni2_TestJniCpp_test+0x20> 795:   00  796:   66 0f ef c0             pxor   %xmm0,%xmm0 79a:   66 0f 38 25 d1          pmovsxdq %xmm1,%xmm2 79f:   83 c1 01                add    $0x1,%ecx 7a2:   66 0f d4 c2             paddq  %xmm2,%xmm0 7a6:   66 0f 6f d1             movdqa %xmm1,%xmm2 7aa:   66 0f 73 da 08          psrldq $0x8,%xmm2 7af:   39 c8                   cmp    %ecx,%eax 7b1:   66 0f 38 25 d2          pmovsxdq %xmm2,%xmm2 7b6:   66 0f fe cb             paddd  %xmm3,%xmm1 7ba:   66 0f d4 c2             paddq  %xmm2,%xmm0 7be:   77 da                   ja     79a <_Z9testWhilei+0x3a> 7c0:   66 0f 6f c8             movdqa %xmm0,%xmm1 7c4:   39 d6                   cmp    %edx,%esi 7c6:   66 0f 73 d9 08          psrldq $0x8,%xmm1 7cb:   66 0f d4 c1             paddq  %xmm1,%xmm0 7cf:   66 48 0f 7e c0          movq   %xmm0,%rax 7d4:   0f 84 ee 00 00 00       je     8c8 <_Z9testWhilei+0x168> 7da:   48 63 ca                movslq %edx,%rcx 7dd:   48 01 c8                add    %rcx,%rax 7e0:   8d 4a 01                lea    0x1(%rdx),%ecx 7e3:   39 cf                   cmp    %ecx,%edi 7e5:   0f 8c d5 00 00 00       jl     8c0 <_Z9testWhilei+0x160> 7eb:   48 63 c9                movslq %ecx,%rcx 7ee:   48 01 c8                add    %rcx,%rax 7f1:   8d 4a 02                lea    0x2(%rdx),%ecx 7f4:   39 cf                   cmp    %ecx,%edi 7f6:   0f 8c c4 00 00 00       jl     8c0 <_Z9testWhilei+0x160> 7fc:   48 63 c9                movslq %ecx,%rcx 7ff:   48 01 c8                add    %rcx,%rax 802:   8d 4a 03                lea    0x3(%rdx),%ecx 805:   39 cf                   cmp    %ecx,%edi 807:   0f 8c b3 00 00 00       jl     8c0 <_Z9testWhilei+0x160> 80d:   48 63 c9                movslq %ecx,%rcx 810:   48 01 c8                add    %rcx,%rax 813:   8d 4a 04                lea    0x4(%rdx),%ecx 816:   39 cf                   cmp    %ecx,%edi 818:   0f 8c a2 00 00 00       jl     8c0 <_Z9testWhilei+0x160> 81e:   48 63 c9                movslq %ecx,%rcx 821:   48 01 c8                add    %rcx,%rax 824:   8d 4a 05                lea    0x5(%rdx),%ecx 827:   39 cf                   cmp    %ecx,%edi 829:   0f 8c 91 00 00 00       jl     8c0 <_Z9testWhilei+0x160> 82f:   48 63 c9                movslq %ecx,%rcx 832:   48 01 c8                add    %rcx,%rax 835:   8d 4a 06                lea    0x6(%rdx),%ecx 838:   39 cf                   cmp    %ecx,%edi 83a:   0f 8c 80 00 00 00       jl     8c0 <_Z9testWhilei+0x160> 840:   48 63 c9                movslq %ecx,%rcx 843:   48 01 c8                add    %rcx,%rax 846:   8d 4a 07                lea    0x7(%rdx),%ecx 849:   39 cf                   cmp    %ecx,%edi 84b:   7c 73                   jl     8c0 <_Z9testWhilei+0x160> 84d:   48 63 c9                movslq %ecx,%rcx 850:   48 01 c8                add    %rcx,%rax 853:   8d 4a 08                lea    0x8(%rdx),%ecx 856:   39 cf                   cmp    %ecx,%edi 858:   7c 66                   jl     8c0 <_Z9testWhilei+0x160> 85a:   48 63 c9                movslq %ecx,%rcx 85d:   48 01 c8                add    %rcx,%rax 860:   8d 4a 09                lea    0x9(%rdx),%ecx 863:   39 cf                   cmp    %ecx,%edi 865:   7c 59                   jl     8c0 <_Z9testWhilei+0x160> 867:   48 63 c9                movslq %ecx,%rcx 86a:   48 01 c8                add    %rcx,%rax 86d:   8d 4a 0a                lea    0xa(%rdx),%ecx 870:   39 cf                   cmp    %ecx,%edi 872:   7c 4c                   jl     8c0 <_Z9testWhilei+0x160> 874:   48 63 c9                movslq %ecx,%rcx 877:   48 01 c8                add    %rcx,%rax 87a:   8d 4a 0b                lea    0xb(%rdx),%ecx 87d:   39 cf                   cmp    %ecx,%edi 87f:   7c 3f                   jl     8c0 <_Z9testWhilei+0x160> 881:   48 63 c9                movslq %ecx,%rcx 884:   48 01 c8                add    %rcx,%rax 887:   8d 4a 0c                lea    0xc(%rdx),%ecx 88a:   39 cf                   cmp    %ecx,%edi 88c:   7c 32                   jl     8c0 <_Z9testWhilei+0x160> 88e:   48 63 c9                movslq %ecx,%rcx 891:   48 01 c8                add    %rcx,%rax 894:   8d 4a 0d                lea    0xd(%rdx),%ecx 897:   39 cf                   cmp    %ecx,%edi 899:   7c 25                   jl     8c0 <_Z9testWhilei+0x160> 89b:   48 63 c9                movslq %ecx,%rcx 89e:   83 c2 0e                add    $0xe,%edx 8a1:   48 01 c8                add    %rcx,%rax 8a4:   39 d7                   cmp    %edx,%edi 8a6:   7c 38                   jl     8e0 <_Z9testWhilei+0x180> 8a8:   48 63 d2                movslq %edx,%rdx 8ab:   48 01 d0                add    %rdx,%rax 8ae:   c3                      retq    8af:   90                      nop 8b0:   31 c0                   xor    %eax,%eax 8b2:   66 66 66 66 66 2e 0f    data16 data16 data16 data16 nopw %cs:0x0(%rax,%rax,1) 8b9:   1f 84 00 00 00 00 00  8c0:   c3                      retq    8c1:   0f 1f 80 00 00 00 00    nopl   0x0(%rax) 8c8:   c3                      retq    8c9:   0f 1f 80 00 00 00 00    nopl   0x0(%rax) 8d0:   31 c0                   xor    %eax,%eax 8d2:   31 d2                   xor    %edx,%edx 8d4:   e9 01 ff ff ff          jmpq   7da <_Z9testWhilei+0x7a> 8d9:   0f 1f 80 00 00 00 00    nopl   0x0(%rax) 8e0:   c3                      retq    8e1:   66 66 66 66 66 66 2e    data16 data16 data16 data16 data16 nopw %cs:0x0(%rax,%rax,1) 8e8:   0f 1f 84 00 00 00 00  8ef:   00 

x86的循环结构

32位的x86,仍然动用MMX等SIMD技术来处理这个小循环。

00000650 <_Z9testWhilei>: 650:   57                      push   %edi 651:   56                      push   %esi 652:   53                      push   %ebx 653:   e8 c8 ff ff ff          call   620 <__cxa_finalize@plt+0xc0> 658:   81 c3 90 19 00 00       add    $0x1990,%ebx 65e:   8b 4c 24 10             mov    0x10(%esp),%ecx 662:   85 c9                   test   %ecx,%ecx 664:   0f 88 f6 00 00 00       js     760 <_Z9testWhilei+0x110> 66a:   8d 41 fd                lea    -0x3(%ecx),%eax 66d:   8d 71 01                lea    0x1(%ecx),%esi 670:   c1 e8 02                shr    $0x2,%eax 673:   83 c0 01                add    $0x1,%eax 676:   83 f9 0d                cmp    $0xd,%ecx 679:   8d 14 85 00 00 00 00    lea    0x0(,%eax,4),%edx 680:   0f 8e ca 00 00 00       jle    750 <_Z9testWhilei+0x100> 686:   66 0f 6f 93 c8 ea ff    movdqa -0x1538(%ebx),%xmm2 68d:   ff  68e:   31 ff                   xor    %edi,%edi 690:   66 0f 6f 83 b8 ea ff    movdqa -0x1548(%ebx),%xmm0 697:   ff  698:   66 0f ef c9             pxor   %xmm1,%xmm1 69c:   83 c7 01                add    $0x1,%edi 69f:   66 0f fe c8             paddd  %xmm0,%xmm1 6a3:   39 f8                   cmp    %edi,%eax 6a5:   66 0f fe c2             paddd  %xmm2,%xmm0 6a9:   77 f1                   ja     69c <_Z9testWhilei+0x4c> 6ab:   66 0f 6f c1             movdqa %xmm1,%xmm0 6af:   39 d6                   cmp    %edx,%esi 6b1:   66 0f 73 d8 08          psrldq $0x8,%xmm0 6b6:   66 0f fe c8             paddd  %xmm0,%xmm1 6ba:   66 0f 6f c1             movdqa %xmm1,%xmm0 6be:   66 0f 73 d8 04          psrldq $0x4,%xmm0 6c3:   66 0f fe c8             paddd  %xmm0,%xmm1 6c7:   66 0f 7e c8             movd   %xmm1,%eax 6cb:   74 79                   je     746 <_Z9testWhilei+0xf6> 6cd:   8d 72 01                lea    0x1(%edx),%esi 6d0:   01 d0                   add    %edx,%eax 6d2:   39 f1                   cmp    %esi,%ecx 6d4:   7c 70                   jl     746 <_Z9testWhilei+0xf6> 6d6:   01 f0                   add    %esi,%eax 6d8:   8d 72 02                lea    0x2(%edx),%esi 6db:   39 f1                   cmp    %esi,%ecx 6dd:   7c 67                   jl     746 <_Z9testWhilei+0xf6> 6df:   01 f0                   add    %esi,%eax 6e1:   8d 72 03                lea    0x3(%edx),%esi 6e4:   39 f1                   cmp    %esi,%ecx 6e6:   7c 5e                   jl     746 <_Z9testWhilei+0xf6> 6e8:   01 f0                   add    %esi,%eax 6ea:   8d 72 04                lea    0x4(%edx),%esi 6ed:   39 f1                   cmp    %esi,%ecx 6ef:   7c 55                   jl     746 <_Z9testWhilei+0xf6> 6f1:   01 f0                   add    %esi,%eax 6f3:   8d 72 05                lea    0x5(%edx),%esi 6f6:   39 f1                   cmp    %esi,%ecx 6f8:   7c 4c                   jl     746 <_Z9testWhilei+0xf6> 6fa:   01 f0                   add    %esi,%eax 6fc:   8d 72 06                lea    0x6(%edx),%esi 6ff:   39 f1                   cmp    %esi,%ecx 701:   7c 43                   jl     746 <_Z9testWhilei+0xf6> 703:   01 f0                   add    %esi,%eax 705:   8d 72 07                lea    0x7(%edx),%esi 708:   39 f1                   cmp    %esi,%ecx 70a:   7c 3a                   jl     746 <_Z9testWhilei+0xf6> 70c:   01 f0                   add    %esi,%eax 70e:   8d 72 08                lea    0x8(%edx),%esi 711:   39 f1                   cmp    %esi,%ecx 713:   7c 31                   jl     746 <_Z9testWhilei+0xf6> 715:   01 f0                   add    %esi,%eax 717:   8d 72 09                lea    0x9(%edx),%esi 71a:   39 f1                   cmp    %esi,%ecx 71c:   7c 28                   jl     746 <_Z9testWhilei+0xf6> 71e:   01 f0                   add    %esi,%eax 720:   8d 72 0a                lea    0xa(%edx),%esi 723:   39 f1                   cmp    %esi,%ecx 725:   7c 1f                   jl     746 <_Z9testWhilei+0xf6> 727:   01 f0                   add    %esi,%eax 729:   8d 72 0b                lea    0xb(%edx),%esi 72c:   39 f1                   cmp    %esi,%ecx 72e:   7c 16                   jl     746 <_Z9testWhilei+0xf6> 730:   01 f0                   add    %esi,%eax 732:   8d 72 0c                lea    0xc(%edx),%esi 735:   39 f1                   cmp    %esi,%ecx 737:   7c 0d                   jl     746 <_Z9testWhilei+0xf6> 739:   83 c2 0d                add    $0xd,%edx 73c:   01 f0                   add    %esi,%eax 73e:   39 d1                   cmp    %edx,%ecx 740:   8d 34 10                lea    (%eax,%edx,1),%esi 743:   0f 4d c6                cmovge %esi,%eax 746:   5b                      pop    %ebx 747:   5e                      pop    %esi 748:   5f                      pop    %edi 749:   c3                      ret     74a:   8d b6 00 00 00 00       lea    0x0(%esi),%esi 750:   31 c0                   xor    %eax,%eax 752:   31 d2                   xor    %edx,%edx 754:   e9 74 ff ff ff          jmp    6cd <_Z9testWhilei+0x7d> 759:   8d b4 26 00 00 00 00    lea    0x0(%esi,%eiz,1),%esi 760:   31 c0                   xor    %eax,%eax 762:   eb e2                   jmp    746 <_Z9testWhilei+0xf6> 764:   8d b6 00 00 00 00       lea    0x0(%esi),%esi 76a:   8d bf 00 00 00 00       lea    0x0(%edi),%edi

循环结构的OAT生成代码

我们还是以第一个为例吧,Dalvik代码生成如下,看起来还是蛮清晰的。

  13: long com.yunos.xulun.testcppjni2.TestART.testWhile(int) (dex_method_idx=16790)    DEX CODE:      0x0000: 1200                      | const/4 v0, #+0      0x0001: 1602 0000                 | const-wide/16 v2, #+0      0x0003: 3660 0700                 | if-gt v0, v6, +7      0x0005: 8104                      | int-to-long v4, v0      0x0006: bb42                      | add-long/2addr v2, v4      0x0007: d800 0001                 | add-int/lit8 v0, v0, #+1      0x0009: 28fa                      | goto -6      0x000a: 1002                      | return-wide v2

翻译成arm64之后,比前面C++译出来的高大上的NEON指令的可是要朴素多了。

    CODE: (code_offset=0x00502d5c size_offset=0x00502d58 size=160)...      0x00502d5c: d1400bf0  sub x16, sp, #0x2000 (8192)      0x00502d60: b940021f  ldr wzr, [x16]      suspend point dex PC: 0x0000      0x00502d64: f81d0fe0  str x0, [sp, #-48]!      0x00502d68: f90017fe  str lr, [sp, #40]      0x00502d6c: b9003be1  str w1, [sp, #56]      0x00502d70: 79400250  ldrh w16, [tr] (state_and_flags)      0x00502d74: 35000390  cbnz w16, #+0x70 (addr 0x502de4)

前面例行公事的我们前几章已经分析过了,只有一个参数在w1中,存到sp+56位置。
循环变量用sp+12,和的结果是sp+20。

      0x00502d78: 52800010  mov w16, #0x0      0x00502d7c: b9000ff0  str w16, [sp, #12]      0x00502d80: d2800010  mov x16, #0x0      0x00502d84: f80143f0  stur x16, [sp, #20]

循环控制变量和传进来的值做比较,如果大于则跳到0x502dd4,将sp+20和的结果传给x0,准备返回。

      0x00502d88: b9400fe0  ldr w0, [sp, #12]      0x00502d8c: b9403be1  ldr w1, [sp, #56]      0x00502d90: 6b01001f  cmp w0, w1      0x00502d94: 1a9fd7e2  cset w2, gt      0x00502d98: 2a0203e0  mov w0, w2      0x00502d9c: 350001c0  cbnz w0, #+0x38 (addr 0x502dd4)

不大于的话,先把循环控制变量读到w0,然后扩展成64位的。存到另一个位置sp+28中。
将sp+20的和,与sp+28循环当前值加起来。存回sp+20.

      0x00502da0: b9400fe0  ldr w0, [sp, #12]      0x00502da4: 93407c01  sxtw x1, w0      0x00502da8: f801c3e1  stur x1, [sp, #28]      0x00502dac: f84143e0  ldur x0, [sp, #20]      0x00502db0: f841c3e1  ldur x1, [sp, #28]      0x00502db4: 8b010002  add x2, x0, x1      0x00502db8: f80143e2  stur x2, [sp, #20]

sp+12的循环控制变量读进来,加1,存回去。检查一下state,是不是要suspend。不是的话,跳回0x502d88,就是循环变量与传进来的值做比较的那一行,继续循环。

      0x00502dbc: b9400fe0  ldr w0, [sp, #12]      0x00502dc0: 11000401  add w1, w0, #0x1 (1)      0x00502dc4: b9000fe1  str w1, [sp, #12]      0x00502dc8: 79400250  ldrh w16, [tr] (state_and_flags)      0x00502dcc: 35000130  cbnz w16, #+0x24 (addr 0x502df0)      0x00502dd0: 17ffffee  b #-0x48 (addr 0x502d88)      0x00502dd4: f84143e0  ldur x0, [sp, #20]      0x00502dd8: f94017fe  ldr lr, [sp, #40]      0x00502ddc: 9100c3ff  add sp, sp, #0x30 (48)      0x00502de0: d65f03c0  ret

后面还是判断pTestSuspend的地方,这次有两处,它们对应的dex PC不同。

      0x00502de4: f9421e5e  ldr lr, [tr, #1080] (pTestSuspend)      0x00502de8: d63f03c0  blr lr      suspend point dex PC: 0x0000      0x00502dec: 17ffffe3  b #-0x74 (addr 0x502d78)      0x00502df0: f9421e5e  ldr lr, [tr, #1080] (pTestSuspend)      0x00502df4: d63f03c0  blr lr      suspend point dex PC: 0x0009      0x00502df8: 17fffff6  b #-0x28 (addr 0x502dd0)
0 0
原创粉丝点击