汇编基础(九)switch汇编分析

引言

最近工作比较忙,没怎么去研究汇编的内容,这么多天,感觉有点生疏,有的时候累死累活很晚才回来,还要在学习别的东西,在写一些总结,力不从心,就算是强迫自己去写去学习,我认为效率也是低下的。这种情况,既影响了第二天的工作,学习的时候也不会太过专注,只为一味的应付了事,学习是一个枯燥、兴趣使向、有目的性的

一些概念上的内容,其实光看光听、光说不练,基本上也就相当于拍脑袋做事情,正儿八经的研究应该是:构思->过程->验证 往往复复每次都会有新的体会

switch 注意事项

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

switch高级代码 <4选项

void funcC(int a ){
    switch (a) {
        case 0:
            printf("yuanying");  //元婴
            break;
        case 1:
            printf("fenshen");  //分身
            break;
        case 2:
            printf("dujie");   //渡劫
            break;
        default:
            printf("qiongsi");    //穷死
            break;
    }
}
int main(int argc, char * argv[]) {
    funcC(2);
    return 0;
}

汇编代码

汇编Switch`funcC:
    0x10475a82c <+0>:   sub    sp, sp, #0x30             ; =0x30 
    0x10475a830 <+4>:   stp    x29, x30, [sp, #0x20]
    0x10475a834 <+8>:   add    x29, sp, #0x20            ; =0x20 
    0x10475a838 <+12>:  stur   w0, [x29, #-0x4]
->  0x10475a83c <+16>:  ldur   w0, [x29, #-0x4]
    0x10475a840 <+20>:  mov    x8, x0
    0x10475a844 <+24>:  stur   w8, [x29, #-0x8]
    0x10475a848 <+28>:  cbz    w0, 0x10475a878           ; <+76> at main.m:17
    0x10475a84c <+32>:  b      0x10475a850               ; <+36> at main.m
    0x10475a850 <+36>:  ldur   w8, [x29, #-0x8]
    0x10475a854 <+40>:  subs   w9, w8, #0x1              ; =0x1 
    0x10475a858 <+44>:  stur   w9, [x29, #-0xc]
    0x10475a85c <+48>:  b.eq   0x10475a88c               ; <+96> at main.m:20
    0x10475a860 <+52>:  b      0x10475a864               ; <+56> at main.m
    0x10475a864 <+56>:  ldur   w8, [x29, #-0x8]
    0x10475a868 <+60>:  subs   w9, w8, #0x2              ; =0x2 
    0x10475a86c <+64>:  str    w9, [sp, #0x10]
    0x10475a870 <+68>:  b.eq   0x10475a8a0               ; <+116> at main.m:23
    0x10475a874 <+72>:  b      0x10475a8b4               ; <+136> at main.m:26
    0x10475a878 <+76>:  adrp   x0, 1
    0x10475a87c <+80>:  add    x0, x0, #0xf10            ; =0xf10 
    0x10475a880 <+84>:  bl     0x10475abe0               ; symbol stub for: printf
    0x10475a884 <+88>:  str    w0, [sp, #0xc]
    0x10475a888 <+92>:  b      0x10475a8c4               ; <+152> at main.m:29
    0x10475a88c <+96>:  adrp   x0, 1
    0x10475a890 <+100>: add    x0, x0, #0xf19            ; =0xf19 
    0x10475a894 <+104>: bl     0x10475abe0               ; symbol stub for: printf
    0x10475a898 <+108>: str    w0, [sp, #0x8]
    0x10475a89c <+112>: b      0x10475a8c4               ; <+152> at main.m:29
    0x10475a8a0 <+116>: adrp   x0, 1
    0x10475a8a4 <+120>: add    x0, x0, #0xf21            ; =0xf21 
    0x10475a8a8 <+124>: bl     0x10475abe0               ; symbol stub for: printf
    0x10475a8ac <+128>: str    w0, [sp, #0x4]
    0x10475a8b0 <+132>: b      0x10475a8c4               ; <+152> at main.m:29
    0x10475a8b4 <+136>: adrp   x0, 1
    0x10475a8b8 <+140>: add    x0, x0, #0xf27            ; =0xf27 
    0x10475a8bc <+144>: bl     0x10475abe0               ; symbol stub for: printf
    0x10475a8c0 <+148>: str    w0, [sp]
    0x10475a8c4 <+152>: ldp    x29, x30, [sp, #0x20]
    0x10475a8c8 <+156>: add    sp, sp, #0x30             ; =0x30 
    0x10475a8cc <+160>: ret    

代码分析

  1. 0x10475a82c 拉伸栈空间
  2. 0x10475a830 保存fp(栈底)、LR(回main函数,funcC函数调用完成以后执行的代码)
  3. 0x10475a834 x29 = sp + #0x20
  4. 0x10475a838 w0 存入到 【x29 - 0x4】
  5. 0x10475a83c 将【x29 - 0x4】的值读入到w0
  6. 0x10475a840 x8 = x0
  7. 0x10475a844 w8存入进【x29 - 0x4】
  8. 0x10475a848 判断w0是否为0 如果为0 直接跳转执行0x10475a878中的方法,不跳转直接向下执行 因为结果是2
    • 0x10475a84c 跳转0x10475a850的方法 0x10475a848 中没有跳转
    • 0x10475a850 w8 = 【x29 - 0x8】
    • 0x10475a854 w9 = w8 - #0x1 修改标记位
    • 0x10475a858【x29- 0x8】 = w9
    • 0x10475a85c 上面的subs是否为0 ,就是等于的意思,等于 执行标记地址的方法的方法0x10475a88c
      • 如果等于执行0x10475a88c adrp x0, 1
      • 0x10475a890 add x0, x0, #0xf19
      • 0x10475a894 bl 0x10475abe0 执行printf函数打印
      • 0x10475a898 保存w0 [sp, #0x8] = w0
      • 0x10475a89c b 0x10475a8c4 跳转(准备返回跳出该函数)
    • 0x10475a860 向下执行0x10475a864标记的方法
    • 0x10475a864 w8 = [x29, #-0x8]
    • 0x10475a868 w9 = w8 - #0x2 修改标记位
    • 0x10475a86c 【sp + 0x10】 = w9
    • 0x10475a870 w9 = w8 - #0x2 是否为0 为0 执行标记地址中的方法 0x10475a8a0 不为0直接往下走
      • 0x10475a874 上面的结果没有跳转,执行标记地址(0x10475a8b4)中的方法
      • 下面的内容
      • 0x10475a8b4 <+136>: adrp x0, 1
      • 0x10475a8b8 <+140>: add x0, x0, #0xf27 ; =0xf27
      • 0x10475a8bc <+144>: bl 0x10475abe0 ; symbol stub for: printf
        以上是找到一个常量、并打印
        以下是0x10475a870 执行的标记地址中的方法
      • 0x10475a8a0 <+116>: adrp x0, 1
      • 0x10475a8a4 <+120>: add x0, x0, #0xf21 ; =0xf21
      • 0x10475a8a8 <+124>: bl 0x10475abe0
        以上是找到常量或局部变量
      • 0x10475a8ac [sp, #0x4] = w0
      • 0x10475a8b0 执行标记地址中的方法0x10475a8c4
  9. 0x10475a878 <+76>: adrp x0, 1
  10. 0x10475a87c <+80>: add x0, x0, #0xf10 ; =0xf10
    以上找到常量或者局部变量
  11. 0x10475a880 printf打印
  12. 0x10475a884 [sp, #0xc] = w0
  13. 0x10475a888 跳转到0x10475a8c4 直接返回之前函数准备
  • 0x10475a8c0 <+148>: str w0, [sp] 保存 [sp] = w0
  • 0x10475a8c4 <+152>: ldp x29, x30, [sp, #0x20] 恢复 fp lr
  • 0x10475a8c8 <+156>: add sp, sp, #0x30 ; =0x30 恢复栈空间
  • 0x10475a8cc <+160>: ret 返回

Switch超过4个选项汇编高级代码还原

高级代码

- (void)TheSelector:(NSInteger )Index{
    switch (Index) {
        case 0:
        {
        }
            break;
        case 1:
        {
        }
            break;
        case 2:
        {
        }
            break;
        case 3:
        {
        }
            break;
        case 4:
        {
        }
            break;
        case 5:
        {
        }
            break;
        default:
            break;
    }
}

高级代码还原`-[ViewController TheSelector:]:
   0x10427e69c <+0>:  sub    sp, sp, #0x30             ; =0x30 
   0x10427e6a0 <+4>:  str    x0, [sp, #0x28]
   0x10427e6a4 <+8>:  str    x1, [sp, #0x20]
   0x10427e6a8 <+12>: str    x2, [sp, #0x18]
->  0x10427e6ac <+16>: ldr    x0, [sp, #0x18]
   0x10427e6b0 <+20>: mov    x1, x0
   0x10427e6b4 <+24>: subs   x0, x0, #0x5              ; =0x5 
   0x10427e6b8 <+28>: str    x1, [sp, #0x10]
   0x10427e6bc <+32>: str    x0, [sp, #0x8]
   0x10427e6c0 <+36>: b.hi   0x10427e6f4               ; <+88> at ViewController.m:51
   0x10427e6c4 <+40>: adrp   x8, 0
   0x10427e6c8 <+44>: add    x8, x8, #0x700            ; =0x700 
   0x10427e6cc <+48>: ldr    x9, [sp, #0x10]
   0x10427e6d0 <+52>: ldrsw  x10, [x8, x9, lsl #2]
   0x10427e6d4 <+56>: add    x8, x10, x8
   0x10427e6d8 <+60>: br     x8
   0x10427e6dc <+64>: b      0x10427e6f8               ; <+92> at ViewController.m:54
   0x10427e6e0 <+68>: b      0x10427e6f8               ; <+92> at ViewController.m:54
   0x10427e6e4 <+72>: b      0x10427e6f8               ; <+92> at ViewController.m:54
   0x10427e6e8 <+76>: b      0x10427e6f8               ; <+92> at ViewController.m:54
   0x10427e6ec <+80>: b      0x10427e6f8               ; <+92> at ViewController.m:54
   0x10427e6f0 <+84>: b      0x10427e6f8               ; <+92> at ViewController.m:54
   0x10427e6f4 <+88>: b      0x10427e6f8               ; <+92> at ViewController.m:54
   0x10427e6f8 <+92>: add    sp, sp, #0x30             ; =0x30 
   0x10427e6fc <+96>: ret  

分开分析

  • 0x10427e69c <+0>: sub sp, sp, #0x30 ; =0x30
    拉伸栈空间
  • 0x10427e6a0 <+4>: str x0, [sp, #0x28]
    0x10427e6a4 <+8>: str x1, [sp, #0x20]
    0x10427e6a8 <+12>: str x2, [sp, #0x18]
    0x10427e6ac <+16>: ldr x0, [sp, #0x18]

    这三句的代码,将x0、x1、x2存入到栈中,然后在把x2存入栈中的值,读出来存到x0,这个过程的含义,大概可以这么理解,因为在OC当中调用方法,是调用一个方法_objc_msgSend,它的三个参数分别是Self、_TheSelector、以及传过来的值,所以最后要读出来x2的值在存入到x0

  • 0x10427e6b0 <+20>: mov x1, x0

    将将x0的值赋值给x1

  • 0x10427e6b4 <+24>: subs x0, x0, #0x5 ; =0x5

x0 = x0 - #0x5 得出的结果将会修改标记位

  • 0x10427e6b8 <+28>: str x1, [sp, #0x10]
    0x10427e6bc <+32>: str x0, [sp, #0x8]

    x1 、x0存入到栈中

  • 0x10427e6c0 <+36>: b.hi 0x10427e6f4

    如果标记位也就是ubs x0, x0, #0x5 x0>#0x5 直接跳转到标记中的地址,当然根据调试我们发现并没有往下走,而且根据我们写的高级代码来说 3肯定没有5大

  • 0x10427e6c4 <+40>: adrp x8, 0
    0x10427e6c8 <+44>: add x8, x8, #0x700 ; =0x700
    ldr x9, [sp, #0x10]

    获取一个全局变量、或者一个常量
    x8得到的结果是-36 x8 中的地址是 猛的一看就是负数


    0x10427e6cc <+48>: ldr x9, [sp, #0x10]

    0x10427e6b8 <+28>: str x1, [sp, #0x10]
    0x10427e6cc <+48>: ldr x9, [sp, #0x10] 因为x1是参数3,x9 = 3


    0x10427e6d0 <+52>: ldrsw x10, [x8, x9, lsl #2]
    0x10427e6d4 <+56>: add x8, x10, x8

x10 = [x8, x9, lsl #2]内存地址中的值
[x8, x9, lsl #2] 以x8为基准值 + (x9的值左移2位 )
以x8地址为基准值 + (3的值左移2位 )
以x8地址为基准值 + (3的值左移2位 )0011 变成 1100 8+4 = 12
以x8地址为基准值 + 12
x10 = 0xffffffe8



直接跳转到指定的case中


结论

  • 其实核心在于
    0x10427e6c4 <+40>: adrp x8, 0
    0x10427e6c8 <+44>: add x8, x8, #0x700
    中拿到的x8,0x100d4e700

**switch中的选项>=4个的话,中间间隔不是很长的话,会直接连续的在栈中创建一个表,每4个字节代表一个数值,比如:case 1、2、3
内存创建的表抽象的对应这些地址:xx FF FF FF = 0 、xx FF FF FF = 1 、xx FF FF FF = 2 、xx FF FF FF = 3,当然最后你需要计算出真正的偏移的位置 **

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容