前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ARM64下switch语句

ARM64下switch语句

原创
作者头像
Wilbur-L
修改2021-02-03 18:07:52
2.1K1
修改2021-02-03 18:07:52
举报
文章被收录于专栏:iOS底层原理iOS底层原理

一·代码

void A(int a){

switch (a){

case 1:

printf("side");

break;

case 2:

printf("other");

break;

default:

printf("nothing");

break;

}

}

二·汇编分析

switch
switch

前三句汇编代码意义参考前面文章

ldur w0,[x29,#-0x4] 从寄存器w0取出数据

cmp w8,#0x1 ;w8-0x1保存到w8里

str w8 ,[sp,#0x8] ;w8再次入栈

b.eq 0x104016218 ;判断w0是否相等于1,是跳转执行相应命令adrp x0,1 add x0,x0,#0xf7d,否执行下一句

b 0x104016208 :ldr w8 #0x2 重复上面的步骤

执行哪一句,取决于main函数调用A时候传入的参数

此时我们多添加几句case,继续研究编译器会对多个case进行什么样的操作

case4
case4

发现疑问:

subs w8,w8,#0x1 w0 - 0x1

cmp x9,#0x3 x9-0x3

str x9,[sp] sp赋值给x9入栈

无论我传入的参数的几,都会执行减一,减三

也就是说如果不是大于4,说明不是default 执行b.hi 0x102f4a220

adrp x8, 0 此时x8保存的是w0-1的结果是subs x8,x8,#0x1

把x8的值赋值给x9

add x8,x8 , #0x238 取出一个地址放到x8里

拿到x8偏移值,口算x8地址:0x102f4a238 后三位 待会会用到

ldr x11,[sp]

ldrsw x10,[x8,x11,lsl #2] x8 + x9 左移2位赋值给x10 = x8 + 4

利用lldb调试读取内存 0x102f4a238 偏移四位读取内存值

x8
x8

读到的内存值为:d8 ff ff ff 存放到x10 (负数)

x9 和 case 有某种的联系。未知

三·旧版本Xcode

不知道是因为Xcode版本不同的原因,旧版本的xcode编译出来的汇编会有一些不同

不一样的地方

mov subs 操作用了cmp替换

四·总结

switch
switch

1.拉伸栈空间,保护x29 x30寄存器

2.subs减去case个数的最小值赋值给x9 - 1

3.cmp x9 #0x3 相当于减去case1 2 3 4

4.把x9-1 -3的值入栈保存

5.然后执行b.hi 说明先switch语句先判断default

6.进入到switch语句核心adrp add ldr ldrsw

7.通过指针偏移计算出switch头的偏移值 0x10007a238 保存在x8里

8.使用lldb x 0x10007a238 可以发现,x8里保存的是switch语句的case表

9.x11寄存器保存的内容会影响去case表里的哪一段负数fffffa8 ffffb8 fffffc8

10.合成真实case地址值 add x9 x8 x10

11.跳转到该代码执行,如果传入的switch的参数是1 那么x9=0

12.如果x9=0 取a8 ff ff ff , 如果x9=1 取b8 ff ff ff 以此类推 也就是为什么ldrsw 需要左移2位

13.计算x9 0xff - a8 =0x57 + 1=0x58 再用x8-0x58得到case的执行地址

14.switch是通过表来储存的,运行效率比较高

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一·代码
  • 二·汇编分析
  • 三·旧版本Xcode
  • 四·总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档