匯編基礎(chǔ)(九)switch匯編分析

引言

最近工作比較忙拳话,沒怎么去研究匯編的內(nèi)容,這么多天种吸,感覺有點(diǎn)生疏弃衍,有的時(shí)候累死累活很晚才回來,還要在學(xué)習(xí)別的東西坚俗,在寫一些總結(jié)镜盯,力不從心,就算是強(qiáng)迫自己去寫去學(xué)習(xí)猖败,我認(rèn)為效率也是低下的速缆。這種情況,既影響了第二天的工作恩闻,學(xué)習(xí)的時(shí)候也不會(huì)太過專注激涤,只為一味的應(yīng)付了事,學(xué)習(xí)是一個(gè)枯燥判呕、興趣使向倦踢、有目的性的

一些概念上的內(nèi)容,其實(shí)光看光聽侠草、光說不練辱挥,基本上也就相當(dāng)于拍腦袋做事情,正兒八經(jīng)的研究應(yīng)該是:構(gòu)思->過程->驗(yàn)證 往往復(fù)復(fù)每次都會(huì)有新的體會(huì)

switch 注意事項(xiàng)

1边涕、假設(shè)switch語句的分支比較少的時(shí)候(例如3晤碘,少于4的時(shí)候沒有意義)沒有必要使用此結(jié)構(gòu),相當(dāng)于if功蜓。
2园爷、各個(gè)分支常量的差值較大的時(shí)候,編譯器會(huì)在效率還是內(nèi)存進(jìn)行取舍式撼,這個(gè)時(shí)候編譯器還是會(huì)編譯成類似于if童社,else的結(jié)構(gòu)。
3著隆、在分支比較多的時(shí)候:在編譯的時(shí)候會(huì)生成一個(gè)表(跳轉(zhuǎn)表每個(gè)地址四個(gè)字節(jié))扰楼。

switch高級代碼 <4選項(xiàng)

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函數(shù)弦赖,funcC函數(shù)調(diào)用完成以后執(zhí)行的代碼)
  3. 0x10475a834 x29 = sp + #0x20
  4. 0x10475a838 w0 存入到 【x29 - 0x4】
  5. 0x10475a83c 將【x29 - 0x4】的值讀入到w0
  6. 0x10475a840 x8 = x0
  7. 0x10475a844 w8存入進(jìn)【x29 - 0x4】
  8. 0x10475a848 判斷w0是否為0 如果為0 直接跳轉(zhuǎn)執(zhí)行0x10475a878中的方法项栏,不跳轉(zhuǎn)直接向下執(zhí)行 因?yàn)榻Y(jié)果是2
    • 0x10475a84c 跳轉(zhuǎn)0x10475a850的方法 0x10475a848 中沒有跳轉(zhuǎn)
    • 0x10475a850 w8 = 【x29 - 0x8】
    • 0x10475a854 w9 = w8 - #0x1 修改標(biāo)記位
    • 0x10475a858【x29- 0x8】 = w9
    • 0x10475a85c 上面的subs是否為0 ,就是等于的意思蹬竖,等于 執(zhí)行標(biāo)記地址的方法的方法0x10475a88c
      • 如果等于執(zhí)行0x10475a88c adrp x0, 1
      • 0x10475a890 add x0, x0, #0xf19
      • 0x10475a894 bl 0x10475abe0 執(zhí)行printf函數(shù)打印
      • 0x10475a898 保存w0 [sp, #0x8] = w0
      • 0x10475a89c b 0x10475a8c4 跳轉(zhuǎn)(準(zhǔn)備返回跳出該函數(shù))
    • 0x10475a860 向下執(zhí)行0x10475a864標(biāo)記的方法
    • 0x10475a864 w8 = [x29, #-0x8]
    • 0x10475a868 w9 = w8 - #0x2 修改標(biāo)記位
    • 0x10475a86c 【sp + 0x10】 = w9
    • 0x10475a870 w9 = w8 - #0x2 是否為0 為0 執(zhí)行標(biāo)記地址中的方法 0x10475a8a0 不為0直接往下走
      • 0x10475a874 上面的結(jié)果沒有跳轉(zhuǎn)沼沈,執(zhí)行標(biāo)記地址(0x10475a8b4)中的方法
      • 下面的內(nèi)容
      • 0x10475a8b4 <+136>: adrp x0, 1
      • 0x10475a8b8 <+140>: add x0, x0, #0xf27 ; =0xf27
      • 0x10475a8bc <+144>: bl 0x10475abe0 ; symbol stub for: printf
        以上是找到一個(gè)常量、并打印
        以下是0x10475a870 執(zhí)行的標(biāo)記地址中的方法
      • 0x10475a8a0 <+116>: adrp x0, 1
      • 0x10475a8a4 <+120>: add x0, x0, #0xf21 ; =0xf21
      • 0x10475a8a8 <+124>: bl 0x10475abe0
        以上是找到常量或局部變量
      • 0x10475a8ac [sp, #0x4] = w0
      • 0x10475a8b0 執(zhí)行標(biāo)記地址中的方法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 跳轉(zhuǎn)到0x10475a8c4 直接返回之前函數(shù)準(zhǔn)備
  • 0x10475a8c0 <+148>: str w0, [sp] 保存 [sp] = w0
  • 0x10475a8c4 <+152>: ldp x29, x30, [sp, #0x20] 恢復(fù) fp lr
  • 0x10475a8c8 <+156>: add sp, sp, #0x30 ; =0x30 恢復(fù)棻也蓿空間
  • 0x10475a8cc <+160>: ret 返回

Switch超過4個(gè)選項(xiàng)匯編高級代碼還原

高級代碼

- (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,這個(gè)過程的含義惭载,大概可以這么理解旱函,因?yàn)樵贠C當(dāng)中調(diào)用方法,是調(diào)用一個(gè)方法_objc_msgSend描滔,它的三個(gè)參數(shù)分別是Self棒妨、_TheSelector、以及傳過來的值含长,所以最后要讀出來x2的值在存入到x0

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

    將將x0的值賦值給x1

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

x0 = x0 - #0x5 得出的結(jié)果將會(huì)修改標(biāo)記位

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

    x1 券腔、x0存入到棧中

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

    如果標(biāo)記位也就是ubs x0, x0, #0x5 x0>#0x5 直接跳轉(zhuǎn)到標(biāo)記中的地址,當(dāng)然根據(jù)調(diào)試我們發(fā)現(xiàn)并沒有往下走拘泞,而且根據(jù)我們寫的高級代碼來說 3肯定沒有5大

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

    獲取一個(gè)全局變量纷纫、或者一個(gè)常量
    x8得到的結(jié)果是-36 x8 中的地址是 猛的一看就是負(fù)數(shù)


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

    0x10427e6b8 <+28>: str x1, [sp, #0x10]
    0x10427e6cc <+48>: ldr x9, [sp, #0x10] 因?yàn)閤1是參數(shù)3,x9 = 3


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

x10 = [x8, x9, lsl #2]內(nèi)存地址中的值
[x8, x9, lsl #2] 以x8為基準(zhǔn)值 + (x9的值左移2位 )
以x8地址為基準(zhǔn)值 + (3的值左移2位 )
以x8地址為基準(zhǔn)值 + (3的值左移2位 )0011 變成 1100 8+4 = 12
以x8地址為基準(zhǔn)值 + 12
x10 = 0xffffffe8



直接跳轉(zhuǎn)到指定的case中


結(jié)論

  • 其實(shí)核心在于
    0x10427e6c4 <+40>: adrp x8, 0
    0x10427e6c8 <+44>: add x8, x8, #0x700
    中拿到的x8陪腌,0x100d4e700

**switch中的選項(xiàng)>=4個(gè)的話辱魁,中間間隔不是很長的話,會(huì)直接連續(xù)的在棧中創(chuàng)建一個(gè)表诗鸭,每4個(gè)字節(jié)代表一個(gè)數(shù)值染簇,比如:case 1、2强岸、3
內(nèi)存創(chuàng)建的表抽象的對應(yīng)這些地址:xx FF FF FF = 0 锻弓、xx FF FF FF = 1 、xx FF FF FF = 2 蝌箍、xx FF FF FF = 3弥咪,當(dāng)然最后你需要計(jì)算出真正的偏移的位置 **

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末过蹂,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子聚至,更是在濱河造成了極大的恐慌酷勺,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件扳躬,死亡現(xiàn)場離奇詭異脆诉,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)贷币,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進(jìn)店門击胜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人役纹,你說我怎么就攤上這事偶摔。” “怎么了促脉?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵辰斋,是天一觀的道長。 經(jīng)常有香客問我瘸味,道長宫仗,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任旁仿,我火速辦了婚禮藕夫,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘枯冈。我一直安慰自己毅贮,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布尘奏。 她就那樣靜靜地躺著嫩码,像睡著了一般。 火紅的嫁衣襯著肌膚如雪罪既。 梳的紋絲不亂的頭發(fā)上铸题,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天,我揣著相機(jī)與錄音琢感,去河邊找鬼丢间。 笑死,一個(gè)胖子當(dāng)著我的面吹牛驹针,可吹牛的內(nèi)容都是我干的烘挫。 我是一名探鬼主播,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼饮六!你這毒婦竟也來了其垄?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤卤橄,失蹤者是張志新(化名)和其女友劉穎绿满,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體窟扑,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡喇颁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了嚎货。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片橘霎。...
    茶點(diǎn)故事閱讀 39,953評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖殖属,靈堂內(nèi)的尸體忽然破棺而出姐叁,到底是詐尸還是另有隱情,我是刑警寧澤洗显,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布外潜,位于F島的核電站,受9級特大地震影響墙懂,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜扮念,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一损搬、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧柜与,春花似錦巧勤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至剩瓶,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間城丧,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工枝缔, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蚊惯。 一個(gè)月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓灵临,卻偏偏與公主長得像趴荸,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子赊舶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評論 2 355

推薦閱讀更多精彩內(nèi)容