首页
社区
课程
招聘
[讨论]ARM与Thumb 模式下switch的不同实现
发表于: 2017-12-23 16:12 4022

[讨论]ARM与Thumb 模式下switch的不同实现

2017-12-23 16:12
4022

ARM与Thumb 模式下switch的不同实现

有序switch的具体实现在ARM模式、Thumb模式下都不相同。arm 指令集编译模式下,有序switch 采用跳转表模式。Thumb 模式下,采用的是跳转函数与跳转表结合使用的模式。

ARM 模式下的实现

参考源代码:

#include <stdio.h>
int main ()
{
    int user_in = 0;

    printf("You can input a number:");
    scanf("%d",&user_in);
    printf("The number is : %d\n",user_in);

    switch(user_in){    // 有序switch
        case 4:
            printf("4 boys.\n");
            break;
        case 5:
            printf("5 girls.\n");
            break;
        case 6:
            printf("6 girls.\n");
            break;
        case 7:
            printf("7 girls.\n");
            break;
        default:
            printf("Haha \n");
        };


    printf("below is switch2 \n");
    switch(user_in)
    {
        case 1:
            printf("*1 boys.\n");
            break;
        case 10:
            printf("*10 boys.\n");
            break;
        case 30:
            printf("*30 girls \n");
            break;
        case 45:
            printf("*45 boys.\n");
            break;
        default:
            printf("NNNN \n");
    }


    return 0;
}

有序switch指的是case值是连续的,参考switch(user_in) 的case,该switch的case测试值的区间是4,5,6,7,所以是连续的case值。

 

进入Switch 语句块之前,会对测试数据进行预处理,一般通过减法指令使测试数据向0对齐,也就是最小测试数据为被映射为0,然后将处理后的数值作为索引访问跳转地址表。

 

一般流程如下:

 

数据预处理(一般为减法指令) -> 判断default 条件(cmp) -> PC相对跳转到跳转指令表n项(ADD{FLAG})->跳转表n项强制跳转到n对应代码块。

 

根据代码总结通用格式

sub rx,rx,xx

ADDxx PC,PC,Rx,LSL # 2  // 因为跳转向量表的每一项指令长度都为4字节,LSL#2 对R3 进行x4 寻址。
B xxx1   // 跳转表,跳转表第0项一般为default 跳转向量。 每一个跳转向量都是4字节ARM B指令。
B xxx2
B xxx3
B xxx n

xxx2:
 code...
 [b exit]  // 可选,break指令编译后效果
xxx3:
 code...
 [b exit]
xxx4:
 code...
 [b exit]
xxxn:
 code...
 [b exit]
default:
 code....
exit:
xxxx //这里是switch 结构之外的代码

switch 的 case块的代码执行完后必须要break的谜团就在这里,因为在编译后每一个case的代码块也是连续的,需要手动的将程序流程改向switch 外部。

 

参考如下,R3为switch 输入测试数据。

.text:00000594                 SUB     R3, R3, #4     //R3 减去4向0对齐
.text:00000598                 CMP     R3, #3         //(最大值7 - 4 = 3,与3比较。)
.text:0000059C                 ADDLS   PC, PC, R3,LSL#2 //PC相对寻址
// 相对寻址公式: PC = PC + R3 * 4 
// 在ARM模式下,PC的值为当前指令地址 + 8 ,R3最终被作为索引。
// 如果R3 = 0,所以当case 0成立时 跳转的目标地址为:0x59C + 0x8 = 0x5A4,在该地址之前还有0x5A0,则为default 实现的代码。
// 

.text:000005A0 ; ---------------------------------------------------------------------------
.text:000005A0 
.text:000005A0 loc_5A0                                 ; 这个是default 跳转
.text:000005A0                 B       loc_604         ; jumptable 0000059C default case
.text:000005A4 ; ---------------------------------------------------------------------------
.text:000005A4
.text:000005A4 loc_5A4                                 ; 这个是case 0+4
.text:000005A4                 B       loc_5B4         ; jumptable 0000059C case 0
.text:000005A8 ; ---------------------------------------------------------------------------
.text:000005A8
.text:000005A8 loc_5A8                                 ; 这个是case 1+4
.text:000005A8                 B       loc_5C8         ; jumptable 0000059C case 1
.text:000005AC ; ---------------------------------------------------------------------------
.text:000005AC
.text:000005AC loc_5AC                                 ; 这个是case 2+4
.text:000005AC                 B       loc_5DC         ; jumptable 0000059C case 2
.text:000005B0 ; ---------------------------------------------------------------------------
.text:000005B0
.text:000005B0 loc_5B0                                 ; 这个是case 3+4
.text:000005B0                 B       loc_5F0         ; jumptable 0000059C case 3
.text:000005B4 ; ---------------------------------------------------------------------------
.text:000005B4
.text:000005B4 loc_5B4                                 ; 这个是switch之外的代码块。
.text:000005B4                                         ; main:loc_5A4↑j

每一个独立的代码块格式基本如下

.text:000005B4 loc_5B4                                 ; CODE XREF: main+5C↑j
.text:000005B4                                         ; main:loc_5A4↑j
.text:000005B4                 LDR     R3, =(a4Boys - 0x5C0) ; jumptable 0000059C case 0
.text:000005B8                 ADD     R3, PC, R3      ; "4 boys."
.text:000005BC                 MOV     R0, R3          ; char *
.text:000005C0                 BL      puts
.text:000005C4                 B       loc_614    // 跳到出口,是break 语句所致
.text:000005C8 ; ---------------------------------------------------------------------------
.text:000005C8
.text:000005C8 loc_5C8                                 ; CODE XREF: main+5C↑j
.text:000005C8                                         ; main:loc_5A8↑j
.text:000005C8                 LDR     R3, =(a5Girls - 0x5D4) ; jumptable 0000059C case 1
.text:000005CC                 ADD     R3, PC, R3      ; "5 girls."
.text:000005D0                 MOV     R0, R3          ; char *
.text:000005D4                 BL      puts
.text:000005D8                 B       loc_614 // 跳到出口
.text:000005DC ; ---------------------------------------------------------------------------
.text:000005DC
.text:000005DC loc_5DC                                 ; CODE XREF: main+5C↑j
.text:000005DC                                         ; main:loc_5AC↑j
.text:000005DC                 LDR     R3, =(a6Girls - 0x5E8) ; jumptable 0000059C case 2
.text:000005E0                 ADD     R3, PC, R3      ; "6 girls."
.text:000005E4                 MOV     R0, R3          ; char *
.text:000005E8                 BL      puts
.text:000005EC                 B       loc_614 //跳到出口
.text:000005F0 ; ---------------------------------------------------------------------------
.text:000005F0
.text:000005F0 loc_5F0                                 ; CODE XREF: main+5C↑j
.text:000005F0                                         ; main:loc_5B0↑j
.text:000005F0                 LDR     R3, =(a7Girls - 0x5FC) ; jumptable 0000059C case 3
.text:000005F4                 ADD     R3, PC, R3      ; "7 girls."
.text:000005F8                 MOV     R0, R3          ; char *
.text:000005FC                 BL      puts
.text:00000600                 B       loc_614 // 跳到出口
.text:00000604 ; ---------------------------------------------------------------------------
.text:00000604
.text:00000604 loc_604                                 ; CODE XREF: main+5C↑j
.text:00000604                                         ; main:loc_5A0↑j
.text:00000604                 LDR     R3, =(aHaha - 0x610) ; jumptable 0000059C default case
.text:00000608                 ADD     R3, PC, R3      ; "Haha "
.text:0000060C                 MOV     R0, R3          ; char *
.text:00000610                 BL      puts
.text:00000614                    // 这里就是出口

Thumb 模式下的实现

Thumb 模式下,有序switch 有一些小变化。

 

Thumb 模式下,跳转向量表中将没有default 块的向量,在预处理之后,会首先判断default条件,如果满足default则直接跳转,如果不满足,再调用__gnu_thumb1_case_si 函数跳转,这是一个永远不会返回的函数。Thumb模式下的switch跳转表是纯数值偏移。每一项的值等于代码块地址到跳转表基质的相对偏移。

.text:00000570                 LDR     R3, [SP,#0x10+var_C]
.text:00000572                 SUBS    R3, #4       数据预处理
.text:00000574                 CMP     R3, #3        
.text:00000576                 BHI     def_57A      判断default
.text:00000578                 MOVS    R0, R3        R0 传递参数
.text:0000057A                 BL      __gnu_thumb1_case_si ; switch jump
.text:0000057A ; ---------------------------------------------------------------------------
.text:0000057E                 ALIGN 0x10              这是一个纯数值偏移跳转表。
.text:00000580 jpt_57A         DCD loc_590 - 0x580     ; jump table for switch statement
.text:00000584                 DCD loc_59C - 0x580     ; jumptable 0000057A case 5
.text:00000588                 DCD loc_5A8 - 0x580     ; jumptable 0000057A case 6
.text:0000058C                 DCD loc_5B4 - 0x580     ; jumptable 0000057A case 7
.text:00000590 ; ---------------------------------------------------------------------------
.text:00000590
.text:00000590 loc_590                                 ; CODE XREF: main+3A↑j
.text:00000590                                         ; DATA XREF: main:jpt_57A↑o
.text:00000590                 LDR     R3, =(a4Boys - 0x596) ; jumptable 0000057A case 4
.text:00000592                 ADD     R3, PC          ; "4 boys."
.text:00000594                 MOVS    R0, R3
.text:00000596                 BL      j_puts
.text:0000059A                 B       loc_5CA
.text:0000059C ; ---------------------------------------------------------------------------
.text:0000059C
.text:0000059C loc_59C                                 ; CODE XREF: main+3A↑j
.text:0000059C                                         ; DATA XREF: main+44↑o
.text:0000059C                 LDR     R3, =(a5Girls - 0x5A2) ; jumptable 0000057A case 5
.text:0000059E                 ADD     R3, PC          ; "5 girls."
.text:000005A0                 MOVS    R0, R3
.text:000005A2                 BL      j_puts
.text:000005A6                 B       loc_5CA
.text:000005A8 ; ---------------------------------------------------------------------------
.text:000005A8
.text:000005A8 loc_5A8                                 ; CODE XREF: main+3A↑j
.text:000005A8                                         ; DATA XREF: main+48↑o
.text:000005A8                 LDR     R3, =(a6Girls - 0x5AE) ; jumptable 0000057A case 6
.text:000005AA                 ADD     R3, PC          ; "6 girls."
.text:000005AC                 MOVS    R0, R3
.text:000005AE                 BL      j_puts
.text:000005B2                 B       loc_5CA
.text:000005B4 ; ---------------------------------------------------------------------------
.text:000005B4
.text:000005B4 loc_5B4                                 ; CODE XREF: main+3A↑j
.text:000005B4                                         ; DATA XREF: main+4C↑o
.text:000005B4                 LDR     R3, =(a7Girls - 0x5BA) ; jumptable 0000057A case 7
.text:000005B6                 ADD     R3, PC          ; "7 girls."
.text:000005B8                 MOVS    R0, R3
.text:000005BA                 BL      j_puts
.text:000005BE                 B       loc_5CA
.text:000005C0 ; ---------------------------------------------------------------------------
.text:000005C0
.text:000005C0 def_57A                                 ; CODE XREF: main+36↑j
.text:000005C0                 LDR     R3, =(aHaha - 0x5C6) ; jumptable 0000057A default case
.text:000005C2                 ADD     R3, PC          ; "Haha "
.text:000005C4                 MOVS    R0, R3
.text:000005C6                 BL      j_puts
.text:000005CA
.text:000005CA loc_5CA                                 ; CODE XREF: main+5A↑j

分析辅助跳转函数

.text:00000668 __gnu_thumb1_case_si                    ; CODE XREF: main+3A↑p
.text:00000668                 PUSH    {R0,R1}   // R0 是要判断的case值
.text:0000066A                 MOV     R1, LR    // R1 = 0x57A(调用处地址) + 2(下一条指令相对)
.text:0000066C                 ADDS    R1, #2  // R1 = 0x57A + 2 + 2 = 0x57E
.text:0000066E                 LSRS    R1, R1, #2 
.text:00000670                 LSLS    R0, R0, #2 // 索引case * 4
.text:00000672                 LSLS    R1, R1, #2 // R1 = 0x580 (跳转向量表基地址)
.text:00000674                 LDR     R0, [R1,R0] // 读取向量表第n项偏移地址
.text:00000676                 ADDS    R0, R0, R1  // 将偏移地址加上跳转表基地址得到代码块地址
.text:00000678                 MOV     LR, R0      // 返回地址设置为目标代码块地址
.text:0000067A                 POP     {R0,R1}   
.text:0000067C                 MOV     PC, LR     // 返回

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 0
支持
分享
最新回复 (2)
雪    币: 2141
活跃值: (7226)
能力值: ( LV11,RANK:180 )
在线值:
发帖
回帖
粉丝
2
2018-5-11 11:23
0
雪    币: 2141
活跃值: (7226)
能力值: ( LV11,RANK:180 )
在线值:
发帖
回帖
粉丝
3
大概看了眼,貌似ARM还见过带数据的。
.text:000042A0  96  00  00  8A                                  BHI          def_42BC                ;  jumptable  000042BC  default  case
.text:000042A4  02  01  A0  E1                                  MOV          R0,  R2,LSL#2
.text:000042A8  10  20  8F  E2                                  ADR          R2,  0x42C0
.text:000042AC  10  80  9B  E5                                  LDR          R8,  [R11,#0x10]
.text:000042B0  0C  10  9B  E5                                  LDR          R1,  [R11,#0xC]
.text:000042B4  08  60  9B  E5                                  LDR          R6,  [R11,#8]
.text:000042B8  02  00  90  E7                                  LDR          R0,  [R0,R2]
.text:000042BC  02  F0  80  E0                                  ADD          PC,  R0,  R2            ;  switch  jump
.text:000042BC                          ;  ---------------------------------------------------------------------------
.text:000042C0  18  00  00  00  jpt_42BC                DCD  0x18                                ;  jump  table  for  switch  statement
.text:000042C4  48  00  00  00                                  DCD  0x48
.text:000042C8  8C  00  00  00                                  DCD  0x8C
.text:000042CC  D0  00  00  00                                  DCD  0xD0
.text:000042D0  08  01  00  00                                  DCD  0x108
.text:000042D4  40  01  00  00                                  DCD  0x140
.text:000042D8                          ;  ---------------------------------------------------------------------------
.text:000042D8
.text:000042D8                          loc_42D8                                                                ;  CODE  XREF:  Wencdec_cbc+50↑j
.text:000042D8  01  00  56  E3                                  CMP          R6,  #1                    ;  jumptable  000042BC  case  1
.text:000042DC  58  00  00  BA                                  BLT          loc_4444
.text:000042E0  0F  00  16  E2                                  ANDS        R0,  R6,  #0xF
最后于 2018-10-10 12:19 被爱吃菠菜编辑 ,原因:
2018-5-11 11:36
0
游客
登录 | 注册 方可回帖
返回
//