美文网首页
5、Switch补充内容(汇编的时候,如何找到对应的case)

5、Switch补充内容(汇编的时候,如何找到对应的case)

作者: Jax_YD | 来源:发表于2021-04-06 16:43 被阅读0次

我们在4、全局变量 & 循环选择和判断最后的时候提到了Switch
其中有一点,我们提到了。那么这张是怎么来的,里面又存放了什么数据,今天我们就详细的探讨一下。上一章我们说里面存放是case对应的要执行的代码的地址;其实更准确的讲,存放的是地址的偏移量,是以表头地址为参照的偏移量。大致如下:


表头地址 + case的偏移量,就可以找到对应的case。也就是说Switch并不是去一个一个的遍历每个case。下面我们看一下真实的代码情况:
switch测试代码
看一下func的汇编代码:
func的汇编代码
读取w8里面的值
我们再接着往下分析,我们会看到这样一段代码:
ubfx   x9, x9, #0, #32

这句代码的意思是:将x9的 高32位 清零,然后再将值赋值给x9;或者说将x9的 低32位 取出来,其他的用0补齐,得到的值赋值给x9

那么接下来的代码就是:

//w8里面的值与0x2相减,得到结果是 w8==5
0x1042ae010 <+20>:  subs   w8, w8, #0x2              ; =0x2    

//将x8里面的值赋值给x9 ("注意:这里为什么要用`x8`而不是`w8`;因为上面的相减的结果可能是一个负数,可能会超过32位")
0x1042ae014 <+24>:  mov    x9, x8 

//这一句上面已经解释过了                                      
0x1042ae018 <+28>:  ubfx   x9, x9, #0, #32

//判断x9 和 0x8的大小(cmp指令在上一篇中有讲过)此时的0x8是最大的case与最小的case的差值
//如果 `a` 与最小的case的差值(假定为“N”),比最大的case与最小的case的差值(假定为“M”)小,说明`a` 在最大的case 和 最小的 case 之间。
//所以此时不能跳转 `default`,要进行查表,具体怎么查表我们接着往下看
0x1042ae01c <+32>:  cmp    x9, #0x8                  ; =0x8 

//将`x9`里的值写入`sp`对应的地址中
0x1042ae020 <+36>:  str    x9, [sp]

//无符号大于的判断,根据上面的结果,此时不会跳转`default`,所以接着往下走。(`default`对应的是`0x1042ae080`)
0x1042ae024 <+40>:  b.hi   0x1042ae080               ; <+132> at main.m

不跳转default,汇编代码接着往下执行:

//在执行下面的代码之前,`x8` 里面的值是 "5",是`a`与最小的case的差值
//下面两行代码就不做过多的解释,在上一篇完整中有过详细的解析
//最终`x8`的值是 "0x00000001042ae098"
0x1042ae028 <+44>:  adrp   x8, 0
0x1042ae02c <+48>:  add    x8, x8, #0x98             ; =0x98 

//将`sp`里面对应的地址里面的值取出来,给到`x11`。那么此时x11里面的值就是 “5”;注意上面的 'mov    x9, x8'
0x1042ae030 <+52>:  ldr    x11, [sp]

//将x11里面的值左移2位,得到的结果与x8相加,再得到的结果赋值给x10。
//这句代码的作用就是为了拿到 “表” 中对应的偏移量(偏移量是一个负数,我们下面会讲到)
//执行结果:`x10 = 0xffffffffffffffe8`
0x1042ae034 <+56>:  ldrsw  x10, [x8, x11, lsl #2]

//x8与x10相加,结果赋值给x9,此时x8存储的是表头的地址,表头加上偏移量,就能得到对应的case的地址
//执行结果:`x9 = 0x00000001042ae080`
//0x1042ae080 对应的是`default`的地址
0x1042ae038 <+60>:  add    x9, x8, x10

//跳转到x9里面的地址对应的位置
0x1042ae03c <+64>:  br     x9

这里我们会注意到,此时func函数栈的结尾是:

0x1042ae094 <+152>: ret

而此时`x8`的值是 `0x1042ae098`,由此可以断定,编译器给我们生产的`差值的表`,紧挨着函数调用栈。这样印证了我们最开始讲到的`表`的情况。
偏移量的表
可以看到表里面的都是负数,因为栈顶是大地址,栈底是小地址。

Tips

  • 指针
    我们都知道,指针是占8个字节的。那么指针的自增自减又是怎样的呢?
    指针的自增自减和指针指向的对象有关系,并且还和编译器有关系。
    int
    char
  • 编译优化
    在Xcode中我们可以设置编译优化,这样在生成汇编代码的时候,编译器会根据我们选在的优化等级来进行相应的优化:
    编译优化等级

相关文章

网友评论

      本文标题:5、Switch补充内容(汇编的时候,如何找到对应的case)

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