[arm64]4、循环&选择

2021-12-12  本文已影响0人  史记_d5da

1、cmp(Compare)比较指令

CMP 把一个寄存器的内容和另一个寄存器的内容或立即数进行比较。但不存储结果,只是正确的更改标志。
一般CMP做完判断后会进行跳转,后面通常会跟上B指令!

1.1、if条件判断
int g = 12;
void func(int a,int b){
    if (a > b) {
        g = a;
    }else{
        g = b;
    }
}
int main(int argc, char * argv[]) {
    func(1, 2);
    return 0;
}

func汇编

002--if的识别`func:
    0x10419dfec <+0>:  sub    sp, sp, #0x10             ; =0x10 
->  0x10419dff0 <+4>:  str    w0, [sp, #0xc]
    0x10419dff4 <+8>:  str    w1, [sp, #0x8]
    0x10419dff8 <+12>: ldr    w8, [sp, #0xc]
    0x10419dffc <+16>: ldr    w9, [sp, #0x8]
    0x10419e000 <+20>: subs   w8, w8, w9
    0x10419e004 <+24>: b.le   0x10419e018               ; <+44> at main.m:17:13
    0x10419e008 <+28>: ldr    w8, [sp, #0xc]
    0x10419e00c <+32>: adrp   x9, 7
    0x10419e010 <+36>: str    w8, [x9, #0x498]
    0x10419e014 <+40>: b      0x10419e024               ; <+56> at main.m:19:1
    0x10419e018 <+44>: ldr    w8, [sp, #0x8]
    0x10419e01c <+48>: adrp   x9, 7
    0x10419e020 <+52>: str    w8, [x9, #0x498]
    0x10419e024 <+56>: add    sp, sp, #0x10             ; =0x10 
    0x10419e028 <+60>: ret    
1.2、do while循环

判断条件b.lt

void func() {
    int nSum = 0;
    int i = 0;
    do {
        nSum = nSum + 1;
        i ++;
    } while (i < 100);
}

汇编代码

003--Loop`func:
->  0x1007fdf6c <+0>:  sub    sp, sp, #0x10             ; =0x10 
    0x1007fdf70 <+4>:  str    wzr, [sp, #0xc]
    0x1007fdf74 <+8>:  str    wzr, [sp, #0x8]
// do while 循环
    0x1007fdf78 <+12>: ldr    w8, [sp, #0xc]
    0x1007fdf7c <+16>: add    w8, w8, #0x1              ; =0x1 
    0x1007fdf80 <+20>: str    w8, [sp, #0xc]
    0x1007fdf84 <+24>: ldr    w8, [sp, #0x8]
    0x1007fdf88 <+28>: add    w8, w8, #0x1              ; =0x1 
    0x1007fdf8c <+32>: str    w8, [sp, #0x8]
    0x1007fdf90 <+36>: ldr    w8, [sp, #0x8]
// 与100 比较
    0x1007fdf94 <+40>: subs   w8, w8, #0x64             ; =0x64 
    0x1007fdf98 <+44>: b.lt   0x1007fdf78               ; <+12> at main.m:14:16
    0x1007fdf9c <+48>: add    sp, sp, #0x10             ; =0x10 
    0x1007fdfa0 <+52>: ret 
1.3、while循环

判断条件b.ge

void func() {
    int nSum = 0;
    int i = 0;
    while (i < 100) {
        nSum = nSum + 1;
        i++;
    }
}

汇编代码

003--Loop`func:
->  0x100c65f68 <+0>:  sub    sp, sp, #0x10             ; =0x10 
    0x100c65f6c <+4>:  str    wzr, [sp, #0xc]
    0x100c65f70 <+8>:  str    wzr, [sp, #0x8]
    0x100c65f74 <+12>: ldr    w8, [sp, #0x8]
// 与100 比较 while循环
    0x100c65f78 <+16>: subs   w8, w8, #0x64             ; =0x64 
    0x100c65f7c <+20>: b.ge   0x100c65f9c               ; <+52> at main.m:17:1
    0x100c65f80 <+24>: ldr    w8, [sp, #0xc]
    0x100c65f84 <+28>: add    w8, w8, #0x1              ; =0x1 
    0x100c65f88 <+32>: str    w8, [sp, #0xc]
    0x100c65f8c <+36>: ldr    w8, [sp, #0x8]
    0x100c65f90 <+40>: add    w8, w8, #0x1              ; =0x1 
    0x100c65f94 <+44>: str    w8, [sp, #0x8]
    0x100c65f98 <+48>: b      0x100c65f74               ; <+12> at main.m:13:12
// 循环结束
    0x100c65f9c <+52>: add    sp, sp, #0x10             ; =0x10 
    0x100c65fa0 <+56>: ret    
1.4、for 循环

for 循环和while循环相似

2、Switch

1、假设switch语句的分支比较少的时候(例如3,少于4的时候没有意义)没有必要使用此结构,相当于if。
2、各个分支常量的差值较大的时候,编译器会在效率还是内存进行取舍,这个时候编译器还是会编译成类似于if,else的结构。
3、在分支比较多的时候:在编译的时候会生成一个表(跳转表每个地址四个字节)。

2.1、case条件为三个的时候
void funcA(int a){
    switch (a) {
        case 1:
            printf("1");
            break;
        case 2:
            printf("2");
            break;
        case 3:
            printf("3");
            break;
        default:
            printf("0");
            break;
    }
}

对应汇编代码

004--选择`funcA:
->  0x100255eec <+0>:   sub    sp, sp, #0x20             ; =0x20 
    0x100255ef0 <+4>:   stp    x29, x30, [sp, #0x10]
    0x100255ef4 <+8>:   add    x29, sp, #0x10            ; =0x10 
    0x100255ef8 <+12>:  stur   w0, [x29, #-0x4]
    0x100255efc <+16>:  ldur   w8, [x29, #-0x4]
    0x100255f00 <+20>:  str    w8, [sp, #0x8]
    0x100255f04 <+24>:  subs   w8, w8, #0x1              ; =0x1 
// case 1
    0x100255f08 <+28>:  b.eq   0x100255f28               ; <+60> at main.m
    0x100255f0c <+32>:  ldr    w8, [sp, #0x8]
    0x100255f10 <+36>:  subs   w8, w8, #0x2              ; =0x2 
// case 2
    0x100255f14 <+40>:  b.eq   0x100255f38               ; <+76> at main.m
    0x100255f18 <+44>:  ldr    w8, [sp, #0x8]
    0x100255f1c <+48>:  subs   w8, w8, #0x3              ; =0x3 
// case 3
    0x100255f20 <+52>:  b.eq   0x100255f48               ; <+92> at main.m
    0x100255f24 <+56>:  b      0x100255f58               ; <+108> at main.m
    0x100255f28 <+60>:  adrp   x0, 2
    0x100255f2c <+64>:  add    x0, x0, #0xe0f            ; =0xe0f 
    0x100255f30 <+68>:  bl     0x100256310               ; symbol stub for: printf
    0x100255f34 <+72>:  b      0x100255f64               ; <+120> at main.m:30:1
    0x100255f38 <+76>:  adrp   x0, 2
    0x100255f3c <+80>:  add    x0, x0, #0xe16            ; =0xe16 
    0x100255f40 <+84>:  bl     0x100256310               ; symbol stub for: printf
    0x100255f44 <+88>:  b      0x100255f64               ; <+120> at main.m:30:1
    0x100255f48 <+92>:  adrp   x0, 2
    0x100255f4c <+96>:  add    x0, x0, #0xe1d            ; =0xe1d 
    0x100255f50 <+100>: bl     0x100256310               ; symbol stub for: printf
    0x100255f54 <+104>: b      0x100255f64               ; <+120> at main.m:30:1
    0x100255f58 <+108>: adrp   x0, 2
    0x100255f5c <+112>: add    x0, x0, #0xe24            ; =0xe24 
    0x100255f60 <+116>: bl     0x100256310               ; symbol stub for: printf
    0x100255f64 <+120>: ldp    x29, x30, [sp, #0x10]
    0x100255f68 <+124>: add    sp, sp, #0x20             ; =0x20 
    0x100255f6c <+128>: ret    
2.2、case大于3个

1、现将参数,减去最新case
2、通过表直接映射到具体的case

void funcA(int a){
    switch (a) {//
        case 1:
            printf("a");
            break;
        case 2:
            printf("b");
            break;
        case 3:
            printf("c");
            break;
        case 5:
            printf("d");
            break;
            
        default:
            printf("0");
            break;
    }
}
funcA(4);

对应的汇编代码

004--选择`funcA:
    0x100a2deb4 <+0>:   sub    sp, sp, #0x20             ; =0x20 
    0x100a2deb8 <+4>:   stp    x29, x30, [sp, #0x10]
    0x100a2debc <+8>:   add    x29, sp, #0x10            ; =0x10 
    0x100a2dec0 <+12>:  stur   w0, [x29, #-0x4]
    0x100a2dec4 <+16>:  ldur   w8, [x29, #-0x4]
    0x100a2dec8 <+20>:  subs   w8, w8, #0x1              ; =0x1 
    0x100a2decc <+24>:  str    x8, [sp]
    0x100a2ded0 <+28>:  subs   x8, x8, #0x4              ; =0x4 
    0x100a2ded4 <+32>:  b.hi   0x100a2df34               ; <+128> at main.m
// 开始查表
    0x100a2ded8 <+36>:  ldr    x11, [sp]
    0x100a2dedc <+40>:  adrp   x10, 0
    0x100a2dee0 <+44>:  add    x10, x10, #0xf4c          ; =0xf4c 
    0x100a2dee4 <+48>:  adr    x8, #0x0                  ; <+48> at main.m:12:5
    0x100a2dee8 <+52>:  ldrsw  x9, [x10, x11, lsl #2]
->  0x100a2deec <+56>:  add    x8, x8, x9
// 获取跳转地址br
    0x100a2def0 <+60>:  br     x8
    0x100a2def4 <+64>:  adrp   x0, 2
    0x100a2def8 <+68>:  add    x0, x0, #0xdff            ; =0xdff 
    0x100a2defc <+72>:  bl     0x100a2e300               ; symbol stub for: printf
    0x100a2df00 <+76>:  b      0x100a2df40               ; <+140> at main.m:30:1
    0x100a2df04 <+80>:  adrp   x0, 2
    0x100a2df08 <+84>:  add    x0, x0, #0xe06            ; =0xe06 
    0x100a2df0c <+88>:  bl     0x100a2e300               ; symbol stub for: printf
    0x100a2df10 <+92>:  b      0x100a2df40               ; <+140> at main.m:30:1
    0x100a2df14 <+96>:  adrp   x0, 2
    0x100a2df18 <+100>: add    x0, x0, #0xe0d            ; =0xe0d 
    0x100a2df1c <+104>: bl     0x100a2e300               ; symbol stub for: printf
    0x100a2df20 <+108>: b      0x100a2df40               ; <+140> at main.m:30:1
    0x100a2df24 <+112>: adrp   x0, 2
    0x100a2df28 <+116>: add    x0, x0, #0xe14            ; =0xe14 
    0x100a2df2c <+120>: bl     0x100a2e300               ; symbol stub for: printf
    0x100a2df30 <+124>: b      0x100a2df40               ; <+140> at main.m:30:1
    0x100a2df34 <+128>: adrp   x0, 2
    0x100a2df38 <+132>: add    x0, x0, #0xe1b            ; =0xe1b 
    0x100a2df3c <+136>: bl     0x100a2e300               ; symbol stub for: printf
    0x100a2df40 <+140>: ldp    x29, x30, [sp, #0x10]
    0x100a2df44 <+144>: add    sp, sp, #0x20             ; =0x20 
    0x100a2df48 <+148>: ret    

ldrsw指令

ldrsw x9, [x10, x11, lsl #2]
新的地址值 = x10的地址值 + (x11的值左移两位)
x9 = 取出新的地址值所指向的内容

adrp指令

0x104089f34 <+128>: adrp x0, 2
0x104089f38 <+132>: add x0, x0, #0xe1b ; =0xe1b

  1. 将PC寄存器的低12位清零,得到 0x0000000104089000 (二进制的1位对应16进制的4位,计算机中的内存地址一般用16进制表示,0x开头表示16进制数,所以后16进制数的后三位清零)
    注:PC寄存器中存储的地址是当前要执行的指令地址,低12位清零,代表当前内存页的起始地址
    2、立即数2代表页数,arm64中每一页为4K,即2的12次方。一个数乘以2的12次方,计算机中即是左移12位,即低12位为0。16进制中即低3位为0.
    3、将上述步骤一和步骤二中得到的16进制数相加,得到0x000000010408b000,将0x000000010408b000放入 x0 寄存器
    4、将x0寄存器中的地址值加上0xe1b,得到的结果放入到x0寄存器。
上一篇 下一篇

猜你喜欢

热点阅读