美文网首页
汇编(四)

汇编(四)

作者: 浅墨入画 | 来源:发表于2021-04-11 19:22 被阅读0次

前言:

内存分区是编译器帮我们做的,属于硬件相关。
macho文件是由代码、数据、macho的描述信息等组成
进行下面的学习之前请先了解一下内存五大区
接下来让我们一起来探索全局变量、常量 、静态区的内存

一. 全局变量和常量

创建空工程Demo,为了防止ViewController中OC代码的干扰,我们在main.m文件中编写代码探讨

// main.m文件代码如下
#import <UIKit/UIKit.h>
#import "AppDelegate.h"

int g = 12;

int func(int a,int b){
    printf("haha");
    int c = a + g;
    return c;
}

int main(int argc, char * argv[]) {
    func(1, 2);
    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
image.png

继续执行上面汇编代码到这一步

image.png
// func函数的汇编代码如下
Demo`func:
->  0x104b82170 <+0>:  sub    sp, sp, #0x20             ; =0x20 
    0x104b82174 <+4>:  stp    x29, x30, [sp, #0x10]
    0x104b82178 <+8>:  add    x29, sp, #0x10            ; =0x10 
    // 1 2 两个参数分别入栈
    0x104b8217c <+12>: stur   w0, [x29, #-0x4]
    0x104b82180 <+16>: str    w1, [sp, #0x8]
    // x0寄存器中存的是地址,这个地址是4个字节,存的是 haha
    // 下面这两条指令是怎么得到0x0000000104b83f8d内存地址呢?
    // adrp 全称address page,按页寻找内存地址  这里是先将1这个值左移12位得到0x1000,再把pc寄存器0x104b82184低12位清0得到0x104b82000,两者再相加得到0x104b83000
    // 0x104b83000 再添加0xf8d 得到0x0000000104b83f8d
    0x104b82184 <+20>: adrp   x0, 1
    0x104b82188 <+24>: add    x0, x0, #0xf8d            ; =0xf8d 
    // 调用printf函数
    0x104b8218c <+28>: bl     0x104b825ac               ; symbol stub for: printf
    // 这里拿到参数a 也就是 1 
    0x104b82190 <+32>: ldur   w8, [x29, #-0x4]
    // 这里通过偏移得到 0x104b89570,也就是参数g值为12 
    0x104b82194 <+36>: adrp   x9, 7
    0x104b82198 <+40>: add    x9, x9, #0x570            ; =0x570 
    // 把x9 读到w10寄存器
    0x104b8219c <+44>: ldr    w10, [x9]
    0x104b821a0 <+48>: add    w8, w8, w10
    0x104b821a4 <+52>: str    w8, [sp, #0x4]
    0x104b821a8 <+56>: ldr    w8, [sp, #0x4]
    // 把计算的结果给到x0寄存器,作为返回值
    0x104b821ac <+60>: mov    x0, x8
    0x104b821b0 <+64>: ldp    x29, x30, [sp, #0x10]
    0x104b821b4 <+68>: add    sp, sp, #0x20             ; =0x20 
    0x104b821b8 <+72>: ret 

上面执行完 0x104b82184 <+20>: adrp x0, 1得到0x104b83000,fff是4095加上0就是4096 刚好对应4k,而一页大小是4096,所以这里的0x104b83000刚好是某一页的开始,adrp就意味着是先找到某一页的地址,再加上偏移量#0xf8d找到x0 haha的地址

// 终端执行PAGESIZE得到4096,说明一页大小是4096
hello-world$ PAGESIZE
4096
  • 页号是编译器编译的时候确定的
  • 0x104b82184 <+20>: adrp x0, 1的参照是pc寄存器0x104b82184,以当前这个代码段的地址作为参照
  • 其中偏移值作为参照有两种方式, 第一种从文件起始位置偏移,第二种是当前代码地址偏移,这里是通过当前代码地址偏移进行计算

这里为什么不能直接加到字符串的位置?

  • 因为0x104b82184地址中的前4位 104b是随机获取的,这里只能通过偏移值来找到字符串位置

这里我们做个练习加深对adrp指令的理解?0x1002bf888 <+20>: adrp x0, 2

  • 这里0x是16进制,低12位这里的位指的是bit,也就是后面三个数清0
  • 这里是先将2这个值左移12位得到0x2000
  • 再把pc寄存器0x1002bf888低12位清0得到0x1002bf000
  • 两者再相加得到0x1002c1000

小结
全局adrp与常量drp是一样的,都是通过基值加上偏移来获取。上面两处adrp没法区分是全局变量还是常量,但是可以拿到内存地址在macho中查看是全局变量还是常量。

二. 还原高级代码

下面我们通过反汇编来还原高级代码,这里需要借助工具Hopper,首先修改代码如下

// main.m文件代码如下
#import <UIKit/UIKit.h>
#import "AppDelegate.h"

int g = 12;

int func(int a,int b){
    printf("haha");
    int c = a + g + b;
    return c;
}

int main(int argc, char * argv[]) {
    func(10, 20);
    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}

编译Demo工程,选中Products目录下Demo.app -> Show in Finder -> 右键显示包内容 -> 找到可执行文件Demo -> 把Demo拖入Hopper

image.png image.png

下面我们通过上面工具的汇编代码来还原高级代码

image.png image.png image.png
        ; ================ B E G I N N I N G   O F   P R O C E D U R E ================
                     _func:
// 函数的开始
0000000100006168         sub        sp, sp, #0x20                               ; CODE XREF=_main+32
000000010000616c         stp        x29, x30, [sp, #0x10]
0000000100006170         add        x29, sp, #0x10

// 从这里可以看出函数为两个参数
0000000100006174         stur       w0, [x29, #-0x4]
0000000100006178         str        w1, [sp, #0x8]
// 还原出代码为 func(int a,int b)
func(int a,int b) { }

// 这一段代码调用的是 printf函数
000000010000617c         adrp       x0, #0x100007000                            ; argument #1 for method imp___stubs__printf
// 工具直接定位出常量 haha
0000000100006180         add        x0, x0, #0xf8d                              ; "haha"
0000000100006184         bl         imp___stubs__printf
// 注意这里的0x100007000 是工具已经帮我们计算好了偏移量之后的值,执行完add 计算出内存地址 0000000100007f8d
// 根据Hopper工具,我们可以得出地址为0000000100007f8d  值为haha
// 还原出代码为printf("haha");
printf("haha");

0000000100006188         ldur       w8, [x29, #-0x4]
// 还原出代码为 int w8 = a;
int w8 = a;

000000010000618c         adrp       x9, #0x10000d000
// 这里也定位出全局变量_g
0000000100006190         add        x9, x9, #0x570                              ; _g
// 根据Hopper工具,我们可以得出地址为000000010000d570 值为0x0c也就是12
// 还原出代码为 int g = 12; 注意⚠️ 因为是全局变量(使用烂苹果软件MachOView看出是在data区被改动,所以是全局变量),要写在func函数外面
g;

0000000100006194         ldr        w10, x9
// 还原出代码为 int w10 = g;
int w10 = g;

0000000100006198         add        w8, w8, w10
// 还原出代码为 w8 += w10;
w8 += w10;

000000010000619c         ldr        w10, [sp, #0x8]
// 还原出代码为 int w10 = b;
w10 = b;

00000001000061a0         add        w8, w8, w10
// 还原出代码为 w8 += w10;
w8 += w10;

00000001000061a4         str        w8, [sp, #0x4]
00000001000061a8         ldr        w8, [sp, #0x4]
00000001000061ac         mov        x0, x8
// 还原出代码为 return w8;
return w8;

// 函数的结束
00000001000061b0         ldp        x29, x30, [sp, #0x10]
00000001000061b4         add        sp, sp, #0x20
00000001000061b8         ret

根据上面汇编代码还原简化为下面代码

int g = 12;
func(int a,int b) {
    printf("haha");
    int w8 = a;
    int w10 = g;
    w8 += w10;
    w10 = b;
    w8 += w10;
    return w8;
}

// 接着简化代码如下
int g = 12;
func(int a,int b) {
    printf("haha");
    return b + g + a;
}

通过最终还原的代码与上面代码比对,发现汇编代码还原高级语言代码成功。注意⚠️ 还原代码必须从下往上还原,这就是逆向

三. if的识别

创建空工程002--if的识别,我们还在main.m文件中编写代码探讨

// main.m文件代码如下
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
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 UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}

编译002--if的识别工程,找到可执行文件拖入Hopper,如果不是真机编译,会出现下图情况

image.png image.png

接下来我们用真机编译,可执行文件拖入Hopper

image.png
// func汇编代码如下
   ; ================ B E G I N N I N G   O F   P R O C E D U R E ================
                     _func:
0000000100006188         sub        sp, sp, #0x10                               ; CODE XREF=_main+32
000000010000618c         str        w0, [sp, #0xc]
0000000100006190         str        w1, [sp, #0x8]
0000000100006194         ldr        w8, [sp, #0xc]
0000000100006198         ldr        w9, [sp, #0x8]
// 通过尾数判断func函数,无返回值
// 上面还原出代码为 void func(int a, int b) {  int w8 = a; int w9 = b; }
void func(int a, int b) { 
    int w8 = a;
    int w9 = b;
}

// 两个参数的比较,cmp执行的是减法 不影响目标寄存器w8 w9,只看减法的结果,修改标记寄存器
000000010000619c         cmp        w8, w9
// b.le 相当于 小于等于
00000001000061a0         b.le       loc_1000061b8
// 还原出代码 if (w8 - w9) { }
if (w8 - w9) {  // 小于等于
}

// 执行大于逻辑
00000001000061a4         ldr        w8, [sp, #0xc]
00000001000061a8         adrp       x9, #0x10000d000
00000001000061ac         add        x9, x9, #0x568                              ; _g
00000001000061b0         str        w8, x9
00000001000061b4         b          loc_1000061c8
// 还原出代码 g = b;
g = b;

// 执行小于等于的逻辑
                     loc_1000061b8:
00000001000061b8         ldr        w8, [sp, #0x8]                              ; CODE XREF=_func+24
00000001000061bc         adrp       x9, #0x10000d000
00000001000061c0         add        x9, x9, #0x568                              ; _g
// 根据Hopper工具,我们可以得出地址为000000010000d568 值为0x0c也就是12,还原出代码为 int g = 12;
// 把w8 写入 x9,也就是写入g中
// 这里只能看出w8是4个字节,因为是低32位,这里有可能是Int 也有可能是uInt
00000001000061c4         str        w8, x9
// 还原出代码 g = w8;
g = w8;

                     loc_1000061c8:
00000001000061c8         add        sp, sp, #0x10                               ; CODE XREF=_func+44
00000001000061cc         ret
                     ; endp
// 最终通过汇编代码还原出的高级代码如下
int g = 12;
void func2(int a,int b){
    if (a > b) {
        g = a;
    }else{
        g = b;
    }
}

小结

cmp(Compare)比较指令

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

  • BL 标号:跳转到标号处执行
  • B.GT 标号:比较结果是大于(greater than),执行标号,否则不跳转
  • B.GE 标号:比较结果是大于等于(greater than or equal to),执行标号,否则不跳转
  • B.EQ 标号:比较结果是等于,执行标号,否则不跳转
  • B.HI 标号:比较结果是无符号大于,执行标号,否则不跳转
  • B.LT 标号:比较结果是小于,执行标号,否则不跳转
  • B.LE(less equal) 标号:比较结果是小于等于,执行标号,否则不跳转
  • B.NE(not equal) 标号:比较结果是不等于,执行标号,否则不跳转

注意⚠️ cmp指令下面执行的是 else 条件

四. 循环

创建空工程003--Loop,我们还在main.m文件中编写代码探讨

// main.m文件代码如下
#import <UIKit/UIKit.h>
#import "AppDelegate.h"

int main(int argc, char * argv[]) {
    int nSum = 0;
    int i = 0;
    do {
        nSum = nSum + 1;
        i++;
    } while (i < 100);  
    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}

真机编译,可执行文件拖入Hopper,获取汇编代码

// main汇编代码如下
                          _main:
00000001000061b8         sub        sp, sp, #0x40
00000001000061bc         stp        x29, x30, [sp, #0x30]
00000001000061c0         add        x29, sp, #0x30
00000001000061c4         stur       wzr, [x29, #-0x4]
00000001000061c8         stur       w0, [x29, #-0x8]
00000001000061cc         stur       x1, [x29, #-0x10]
00000001000061d0         stur       wzr, [x29, #-0x14]
// 把0放入一个内存地址中
00000001000061d4         str        wzr, [sp, #0x18]

                     loc_1000061d8:
// 这里是do的操作
00000001000061d8         ldur       w8, [x29, #-0x14]                           ; CODE XREF=_main+64
00000001000061dc         add        w8, w8, #0x1
00000001000061e0         stur       w8, [x29, #-0x14]
// 读出来给到w8寄存器
00000001000061e4         ldr        w8, [sp, #0x18]
// w8寄存器加1
00000001000061e8         add        w8, w8, #0x1
00000001000061ec         str        w8, [sp, #0x18]
00000001000061f0         ldr        w8, [sp, #0x18]
// 比较指令这里是while条件,0x64就是100,和100比较,小于就跳回来
00000001000061f4         cmp        w8, #0x64
00000001000061f8         b.lt       loc_1000061d8

00000001000061fc         ldur       w0, [x29, #-0x8]
0000000100006200         ldur       x1, [x29, #-0x10]
0000000100006204         adrp       x8, #0x10000d000
0000000100006208         add        x8, x8, #0x398                              ; objc_cls_ref_AppDelegate
000000010000620c         ldr        x8, x8
0000000100006210         str        w0, [sp, #0x14]
0000000100006214         mov        x0, x8
0000000100006218         str        x1, [sp, #0x8]
000000010000621c         bl         imp___stubs__objc_opt_class
0000000100006220         bl         imp___stubs__NSStringFromClass
0000000100006224         mov        x29, x29
0000000100006228         bl         imp___stubs__objc_retainAutoreleasedReturnValue
000000010000622c         ldr        w9, [sp, #0x14]
0000000100006230         str        x0, sp
0000000100006234         mov        x0, x9
0000000100006238         ldr        x1, [sp, #0x8]
000000010000623c         movz       x8, #0x0
0000000100006240         mov        x2, x8
0000000100006244         ldr        x3, sp
0000000100006248         bl         imp___stubs__UIApplicationMain
000000010000624c         stur       w0, [x29, #-0x4]
0000000100006250         ldr        x0, sp
0000000100006254         bl         imp___stubs__objc_release
0000000100006258         ldur       w0, [x29, #-0x4]
000000010000625c         ldp        x29, x30, [sp, #0x30]
0000000100006260         add        sp, sp, #0x40
0000000100006264         ret
                        ; endp

修改main.m代码如下

int main(int argc, char * argv[]) {
    int nSum = 0;
    int i = 0;
    while (i < 100) {
        nSum = nSum + 1;
        i++;
    } ;
    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}

// 核心汇编代码如下
                     loc_1000061d4:
00000001000061d4         ldr        w8, [sp, #0x18]                             ; CODE XREF=_main+68
00000001000061d8         cmp        w8, #0x64
// 不满足条件跳转执行loc_1000061fc
00000001000061dc         b.ge       loc_1000061fc

00000001000061e0         ldur       w8, [x29, #-0x14]
00000001000061e4         add        w8, w8, #0x1
00000001000061e8         stur       w8, [x29, #-0x14]
00000001000061ec         ldr        w8, [sp, #0x18]
00000001000061f0         add        w8, w8, #0x1
00000001000061f4         str        w8, [sp, #0x18]
00000001000061f8         b          loc_1000061d4
                     loc_1000061fc:
00000001000061fc         ldur       w0, [x29, #-0x8]                            ; CODE XREF=_main+40
0000000100006200         ldur       x1, [x29, #-0x10]
0000000100006204         adrp       x8, #0x10000d000
0000000100006208         add        x8, x8, #0x398                              ; objc_cls_ref_AppDelegate
000000010000620c         ldr        x8, x8
0000000100006210         str        w0, [sp, #0x14]
0000000100006214         mov        x0, x8
0000000100006218         str        x1, [sp, #0x8]
000000010000621c         bl         imp___stubs__objc_opt_class
0000000100006220         bl         imp___stubs__NSStringFromClass
0000000100006224         mov        x29, x29
... 

再次修改main.m代码如下

int main(int argc, char * argv[]) {
    int nSum = 0;
    for (int i = 0; i < 100; i++) {
        nSum = nSum + 1;
    }
    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}

// 核心汇编代码如下
                     loc_1000061d4:
00000001000061d4         ldr        w8, [sp, #0x14]                             ; CODE XREF=_main+72
00000001000061d8         cmp        w8, #0x64
00000001000061dc         b.ge       loc_1000061fc

00000001000061e0         ldur       w8, [x29, #-0x14]
00000001000061e4         add        w8, w8, #0x1
00000001000061e8         stur       w8, [x29, #-0x14]
00000001000061ec         ldr        w8, [sp, #0x14]
00000001000061f0         add        w8, w8, #0x1
00000001000061f4         str        w8, [sp, #0x14]
00000001000061f8         b          loc_1000061d4

                     loc_1000061fc:
00000001000061fc         ldur       w0, [x29, #-0x8]                            ; CODE XREF=_main+44
0000000100006200         ldur       x1, [x29, #-0x10]
0000000100006204         adrp       x8, #0x10000d000
0000000100006208         add        x8, x8, #0x398                              ; objc_cls_ref_AppDelegate
000000010000620c         ldr        x8, x8
0000000100006210         str        w0, [sp, #0x10]
...
// 可以看出来跟while 汇编代码一摸一样,所以两者可以代替

五. 选择(上)

创建空工程004--选择,我们还在main.m文件中编写代码探讨

// main.m文件代码如下
#import <UIKit/UIKit.h>
#import "AppDelegate.h"

void funcA(int a){
    switch (a) {//
        case 1:
            printf("打坐");
            break;
        case 2:
            printf("加红");
            break;
        case 3:
            printf("加蓝");
            break;
        default:
            printf("啥都不干");
            break;
    }
}
int main(int argc, char * argv[]) {
    funcA(1);
    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
// funcA汇编代码如下
004--选择`funcA:
    0x100962114 <+0>:   sub    sp, sp, #0x20             ; =0x20 
    0x100962118 <+4>:   stp    x29, x30, [sp, #0x10]
    0x10096211c <+8>:   add    x29, sp, #0x10            ; =0x10 
    // wo 寄存器保存一下,然后再取出来
    0x100962120 <+12>:  stur   w0, [x29, #-0x4]
->  0x100962124 <+16>:  ldur   w8, [x29, #-0x4]
    // 比较,相等就跳转
    0x100962128 <+20>:  cmp    w8, #0x1                  ; =0x1 
    0x10096212c <+24>:  str    w8, [sp, #0x8]
    0x100962130 <+28>:  b.eq   0x100962158               ; <+68> at main.m
    0x100962134 <+32>:  b      0x100962138               ; <+36> at main.m
    0x100962138 <+36>:  ldr    w8, [sp, #0x8]
    // 比较,相等就跳转
    0x10096213c <+40>:  cmp    w8, #0x2                  ; =0x2 
    0x100962140 <+44>:  b.eq   0x100962168               ; <+84> at main.m
    0x100962144 <+48>:  b      0x100962148               ; <+52> at main.m
    0x100962148 <+52>:  ldr    w8, [sp, #0x8]
    // 比较,相等就跳转
    0x10096214c <+56>:  cmp    w8, #0x3                  ; =0x3 
    0x100962150 <+60>:  b.eq   0x100962178               ; <+100> at main.m
    0x100962154 <+64>:  b      0x100962188               ; <+116> at main.m
    // 拿出常量打印
    0x100962158 <+68>:  adrp   x0, 1
    0x10096215c <+72>:  add    x0, x0, #0xf6d            ; =0xf6d 
    0x100962160 <+76>:  bl     0x10096258c               ; symbol stub for: printf
    0x100962164 <+80>:  b      0x100962194               ; <+128> at main.m:30:1
    0x100962168 <+84>:  adrp   x0, 1
    0x10096216c <+88>:  add    x0, x0, #0xf74            ; =0xf74 
    0x100962170 <+92>:  bl     0x10096258c               ; symbol stub for: printf
    0x100962174 <+96>:  b      0x100962194               ; <+128> at main.m:30:1
    0x100962178 <+100>: adrp   x0, 1
    0x10096217c <+104>: add    x0, x0, #0xf7b            ; =0xf7b 
    0x100962180 <+108>: bl     0x10096258c               ; symbol stub for: printf
    0x100962184 <+112>: b      0x100962194               ; <+128> at main.m:30:1
    0x100962188 <+116>: adrp   x0, 1
    0x10096218c <+120>: add    x0, x0, #0xf82            ; =0xf82 
    0x100962190 <+124>: bl     0x10096258c               ; symbol stub for: printf
    0x100962194 <+128>: ldp    x29, x30, [sp, #0x10]
    0x100962198 <+132>: add    sp, sp, #0x20             ; =0x20 
    0x10096219c <+136>: ret    
// 可以发现上面汇编代码与if 汇编是一样的

修改main.m代码如下

void funcA(int a){
    switch (a) {//
        case 1:
            printf("打坐");
            break;
        case 2:
            printf("加红");
            break;
        case 3:
            printf("加蓝");
            break;
        case 4:
            printf("打怪");
            break;
        default:
            printf("啥都不干");
            break;
    }
}

// funcA汇编代码如下
004--选择`funcA:
    0x1024660f0 <+0>:   sub    sp, sp, #0x20             ; =0x20 
    0x1024660f4 <+4>:   stp    x29, x30, [sp, #0x10]
    0x1024660f8 <+8>:   add    x29, sp, #0x10            ; =0x10 
    // 参数入栈
    0x1024660fc <+12>:  stur   w0, [x29, #-0x4]
->  0x102466100 <+16>:  ldur   w8, [x29, #-0x4]
    // 这里没有了类似if的汇编,也没有了很多个cmp 
    // subs 让参数减1,这里会影响状态寄存器减1
    0x102466104 <+20>:  subs   w8, w8, #0x1              ; =0x1 
    0x102466108 <+24>:  mov    x9, x8
    0x10246610c <+28>:  ubfx   x9, x9, #0, #32
    // 判断是否等于3
    0x102466110 <+32>:  cmp    x9, #0x3                  ; =0x3 
    0x102466114 <+36>:  str    x9, [sp]
    // 跳转
    0x102466118 <+40>:  b.hi   0x102466174               ; <+132> at main.m
    0x10246611c <+44>:  adrp   x8, 0
    0x102466120 <+48>:  add    x8, x8, #0x18c            ; =0x18c 
    0x102466124 <+52>:  ldr    x11, [sp]
    0x102466128 <+56>:  ldrsw  x10, [x8, x11, lsl #2]
    0x10246612c <+60>:  add    x9, x8, x10
    0x102466130 <+64>:  br     x9
    0x102466134 <+68>:  adrp   x0, 1
    0x102466138 <+72>:  add    x0, x0, #0xf69            ; =0xf69 
    0x10246613c <+76>:  bl     0x102466588               ; symbol stub for: printf
    0x102466140 <+80>:  b      0x102466180               ; <+144> at main.m:30:1
    0x102466144 <+84>:  adrp   x0, 1
    0x102466148 <+88>:  add    x0, x0, #0xf70            ; =0xf70 
    0x10246614c <+92>:  bl     0x102466588               ; symbol stub for: printf
    0x102466150 <+96>:  b      0x102466180               ; <+144> at main.m:30:1
    0x102466154 <+100>: adrp   x0, 1
    0x102466158 <+104>: add    x0, x0, #0xf77            ; =0xf77 
    0x10246615c <+108>: bl     0x102466588               ; symbol stub for: printf
    0x102466160 <+112>: b      0x102466180               ; <+144> at main.m:30:1
    0x102466164 <+116>: adrp   x0, 1
    0x102466168 <+120>: add    x0, x0, #0xf7e            ; =0xf7e 
    0x10246616c <+124>: bl     0x102466588               ; symbol stub for: printf
    0x102466170 <+128>: b      0x102466180               ; <+144> at main.m:30:1
    0x102466174 <+132>: adrp   x0, 1
    0x102466178 <+136>: add    x0, x0, #0xf85            ; =0xf85 
    0x10246617c <+140>: bl     0x102466588               ; symbol stub for: printf
    0x102466180 <+144>: ldp    x29, x30, [sp, #0x10]
    0x102466184 <+148>: add    sp, sp, #0x20             ; =0x20 
    0x102466188 <+152>: ret    

小结

  • switch 如果条件语句小于等于3个,汇编代码就是if else 的形式。
  • 当参数超过3个,就会建立一张连续的数据表,把每一条判断语句做的事情放入表中相应地址,每8个字节放一个地址 ,通过一次运算得到一个地址值,然后执行对应代码,不需要多次if else 判断,这就是底层的优化
  • 这里上面是减1和3比较得到一个index值,通过index值从数据表中找内存地址,找到之后直接执行对应的逻辑

注意⚠️ switch 判断条件比较多的话,一直if else 会浪费时间,由于上面都是连续的数字,这个时候就会创建表,投入空间来换时间。如果上面判断条件不是连续的,底层就不会创建表来进行优化,又会执行if else 的判断。

// 下面这种形式,虽然条件语句是4个,但判断条件不是连续的,系统底层不会创建表来进行优化
void funcA(int a){
    switch (a) {
        case 1:
            printf("打坐");
            break;
        case 200:
            printf("加红");
            break;
        case 35:
            printf("加蓝");
            break;
        case 41:
            printf("打怪");
            break;
        default:
            printf("啥都不干");
            break;
    }
}
  • 连续的表,系统底层会找规律来创建表进行优化
  • 如果判断逻辑是连续的并且超过了3个,尽可能使用switch语句,因为底层会进行优化

上面是怎么生成数据表?又是怎么找到对应的地址值?限于篇幅,我们之后继续探讨......

相关文章

  • <安全攻防之汇编基础>

    &关于汇编基础请点击 <汇编一> <汇编二> <汇编三> <汇编四> <汇编五> <汇编六> <汇编七> <汇编八...

  • 汇编(四)

    DS和[address] CPU要读写一个内存单元时,必须要先给出这个内存单元的地址,在8086中,内存地址由段地...

  • 汇编四

    栈 栈:是一种具有特殊的访问方式的存储空间 后进先出, Last In Out Firt,LIFO 8086提供了...

  • 汇编(四)

    DS和[address] CPU要读写一个内存单元时,必须要先给出这个内存单元的地址,在8086中,内存地址由段地...

  • 汇编(四)

    一. DS和[address] CPU要读写一个内存单元时,必须要给出这个内存单元的地址,在8086中,内存地址有...

  • 汇编(四)

    1. if语句的汇编代码 一个简单的if语句 main函数汇编 2. while语句的汇编代码 do while的...

  • 汇编(四)

    前言: 内存分区是编译器帮我们做的,属于硬件相关。macho文件是由代码、数据、macho的描述信息等组成进行下面...

  • 提高代码执行效率的几个小技巧

    前言 目录 一、方法参数限制 二、反汇编 switch case & if else 三、C 中写汇编代码 四、 ...

  • 汇编语言 学习笔记(三)

    汇编语言学习笔记 四、汇编语言程序格式 语句基本格式 汇编语言程序中的语句由 4 项组成,格式如下: 名字(nam...

  • 汇编四、栈

    栈 栈:是一种具有特殊的访问方式的存储空间(后进先出, Last In Out Firt,LIFO) SP和FP寄...

网友评论

      本文标题:汇编(四)

      本文链接:https://www.haomeiwen.com/subject/xtkakltx.html