Arm逆向

这部分内容跟x86很大程度上都是一样的.

加法

源代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
int main(int argc, char** argv){
    15 + 20;
    int n1 = 0;
    int n2 = 0;
    n1 = n1 + 1;
    n1 = 1 + 2;
    n1 = n1 + n2;
    printf("n1 = %d\n", n1);
    return 0;
}

arm-v7a:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
.text:00002A00 main                                    ; DATA XREF: .text:000029BC↑o
.text:00002A00                                         ; .got:main_ptr↓o
.text:00002A00 argc = R0                               ; int
.text:00002A00 argv = R1                               ; unsigned __int8 **
.text:00002A00 ; __unwind {
.text:00002A00                 PUSH            {R7,LR}
.text:00002A02                 MOV             R7, SP
.text:00002A04                 LDR             argc, =(aN1D - 0x2A0C) ; "n1 = %d\n"
.text:00002A06                 MOVS            argv, #3
.text:00002A08                 ADD             R0, PC  ; "n1 = %d\n"
.text:00002A0A                 BLX             printf
.text:00002A0E                 MOVS            R0, #0
.text:00002A10                 POP             {R7,PC}
.text:00002A10 ; End of function main

arm-v8a:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
.text:00002A00 main                                    ; DATA XREF: .text:000029BC↑o
.text:00002A00                                         ; .got:main_ptr↓o
.text:00002A00 argc = R0                               ; int
.text:00002A00 argv = R1                               ; unsigned __int8 **
.text:00002A00 ; __unwind {
.text:00002A00                 PUSH            {R7,LR}
.text:00002A02                 MOV             R7, SP
.text:00002A04                 LDR             argc, =(aN1D - 0x2A0C) ; "n1 = %d\n"
.text:00002A06                 MOVS            argv, #3
.text:00002A08                 ADD             R0, PC  ; "n1 = %d\n"
.text:00002A0A                 BLX             printf
.text:00002A0E                 MOVS            R0, #0
.text:00002A10                 POP             {R7,PC}
.text:00002A10 ; End of function main

减法

源代码:

1
2
3
4
5
6
7
8
9
int main(int argc, char* argv[]){
    int n1 = argc;
    int n2 = 0;
    scanf("%d", &n2);
    n1 = n1 - 100;
    n1 = n1 + 5 - n2;
    printf("n1 = %d\n", n1);
    return 0;
}

arm-v7a:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
.text:00002A30 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:00002A30                 EXPORT main
.text:00002A30 main                                    ; DATA XREF: .text:000029EC↑o
.text:00002A30                                         ; .got:main_ptr↓o
.text:00002A30
.text:00002A30 var_10          = -0x10
.text:00002A30 var_C           = -0xC
.text:00002A30
.text:00002A30 argc = R0                               ; int
.text:00002A30 argv = R1                               ; unsigned __int8 **
.text:00002A30 ; __unwind {
.text:00002A30                 PUSH            {R4,R5,R7,LR}
.text:00002A32                 ADD             R7, SP, #8
.text:00002A34                 SUB             SP, SP, #8
.text:00002A36                 MOV             R4, argc
.text:00002A38 argc = R4                               ; int
.text:00002A38                 LDR             R0, =(__stack_chk_guard_ptr - 0x2A3E)
.text:00002A3A                 ADD             R0, PC  ; __stack_chk_guard_ptr
.text:00002A3C                 LDR             R5, [R0] ; __stack_chk_guard
.text:00002A3E                 LDR             argv, [R5]
.text:00002A40                 LDR             R0, =(aD - 0x2A4A) ; "%d"
.text:00002A42                 STR             R1, [SP,#0x10+var_C]
.text:00002A44 n1 = R4                                 ; int
.text:00002A44                 MOVS            R1, #0
.text:00002A46                 ADD             R0, PC  ; "%d" ; format
.text:00002A48                 STR             R1, [SP,#0x10+var_10]
.text:00002A4A                 MOV             R1, SP
.text:00002A4C                 BLX             scanf
.text:00002A50 argc = R4                               ; int
.text:00002A50                 LDR             R1, [SP,#0x10+var_10]
.text:00002A52 n2 = R1                                 ; int
.text:00002A52                 LDR             R0, =(aN1D - 0x2A5A) ; "n1 = %d\n"
.text:00002A54                 SUBS            n2, argc, n2
.text:00002A56                 ADD             R0, PC  ; "n1 = %d\n"
.text:00002A58                 SUBS            R1, #0x5F ; '_'
.text:00002A5A n1 = R1                                 ; int
.text:00002A5A                 BLX             printf
.text:00002A5E                 LDR             R0, [SP,#0x10+var_C]
.text:00002A60                 LDR             R1, [R5]
.text:00002A62                 SUBS            R0, R1, R0
.text:00002A64                 ITTT EQ
.text:00002A66                 MOVEQ           R0, #0
.text:00002A68                 ADDEQ           SP, SP, #8
.text:00002A6A                 POPEQ           {argc,R5,R7,PC}
.text:00002A6C                 BLX             __stack_chk_fail
.text:00002A6C ; End of function main

上述中的ITTT EQ指令中有3个T,表示接下来的3条指令是条件执行指令. IT EQ,这是thumb2的指令,是指令前缀.

乘法

源代码:

1
2
3
4
5
6
int main(int argc, char* argv[]){
    int n1 = argc;
    int n2 = argc;
    printf("n1 * 15 = %d\n", n1 *15);
    return 0;
}

arm-v7a:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
.text:00002A00 main                                    ; DATA XREF: .text:000029BC↑o
.text:00002A00                                         ; .got:main_ptr↓o
.text:00002A00 argv = R1                               ; unsigned __int8 **
.text:00002A00 argc = R0                               ; int
.text:00002A00 ; __unwind {
.text:00002A00                 PUSH            {R7,LR}
.text:00002A02                 MOV             R7, SP
.text:00002A04 n2 = R0                                 ; int
.text:00002A04                 LDR             R2, =(aN115D - 0x2A0E) ; "n1 * 15 = %d\n"
.text:00002A06                 RSB.W           argv, n2, n2,LSL#4
.text:00002A0A                 ADD             R2, PC  ; "n1 * 15 = %d\n"
.text:00002A0C                 MOV             n2, R2  ; format
.text:00002A0E                 BLX             printf
.text:00002A12                 MOVS            R0, #0
.text:00002A14                 POP             {R7,PC}
.text:00002A14 ; End of function main

除法

无符号

除数为2的幂(常量)

源代码:

1
printf("argc / 8", (unsigned int)argc / 8);

arm-v7a:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
.text:00002A00 main                                    ; DATA XREF: .text:000029BC↑o
.text:00002A00                                         ; .got:main_ptr↓o
.text:00002A00 argc = R0                               ; int
.text:00002A00 argv = R1                               ; unsigned __int8 **
.text:00002A00 ; __unwind {
.text:00002A00                 PUSH            {R7,LR}
.text:00002A02                 MOV             R7, SP
.text:00002A04                 LDR             R2, =(aArgc8 - 0x2A0C) ; "argc / 8"
.text:00002A06                 LSRS            argv, argc, #3
.text:00002A08                 ADD             R2, PC  ; "argc / 8"
.text:00002A0A                 MOV             argc, R2 ; format
.text:00002A0C                 BLX             printf
.text:00002A10                 MOVS            R0, #0
.text:00002A12                 POP             {R7,PC}
.text:00002A12 ; End of function main
1
2
//右移3位
LSRS            argv, argc, #3

arm-v8a:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
.text:00000000000006A8 main                                    ; DATA XREF: LOAD:0000000000000448↑o
.text:00000000000006A8                                         ; .got:main_ptr↓o
.text:00000000000006A8
.text:00000000000006A8 var_s0          =  0
.text:00000000000006A8
.text:00000000000006A8 argc = X0                               ; int
.text:00000000000006A8 argv = X1                               ; unsigned __int8 **
.text:00000000000006A8 ; __unwind {
.text:00000000000006A8                 STP             X29, X30, [SP,#-0x10+var_s0]!
.text:00000000000006AC                 MOV             X29, SP
.text:00000000000006B0                 LSR             W1, W0, #3
.text:00000000000006B4                 ADRL            X0, aArgc8 ; "argc / 8"
.text:00000000000006BC                 BL              .printf
.text:00000000000006C0                 MOV             W0, WZR
.text:00000000000006C4                 LDP             X29, X30, [SP+var_s0],#0x10
.text:00000000000006C8                 RET
.text:00000000000006C8 ; } // starts at 6A8
.text:00000000000006C8 ; End of function main
1
2
//右移3位
LSR             W1, W0, #3

总结:

1
x / 2^n = x >> n
除数为非2的幂(常量)
MagicNumber无进位

源代码:

1
printf("argc / 9", (unsigned int)argc / 9);

arm-v7a:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
.text:00002A00 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:00002A00                 EXPORT main
.text:00002A00 main                                    ; DATA XREF: .text:000029BC↑o
.text:00002A00                                         ; .got:main_ptr↓o
.text:00002A00 argc = R0                               ; int
.text:00002A00 argv = R1                               ; unsigned __int8 **
.text:00002A00 ; __unwind {
.text:00002A00                 PUSH            {R7,LR}
.text:00002A02                 MOV             R7, SP
.text:00002A04                 MOV             R1, #0x38E38E39
.text:00002A0C                 UMULL.W         argc, R1, argc, R1
.text:00002A10                 LDR             R0, =(aArgc9 - 0x2A16) ; "argc / 9"
.text:00002A12                 ADD             R0, PC  ; "argc / 9"
.text:00002A14                 LSRS            R1, R1, #1
.text:00002A16                 BLX             printf
.text:00002A1A                 MOVS            R0, #0
.text:00002A1C                 POP             {R7,PC}
.text:00002A1C ; End of function main
1
2
3
4
5
6
7
//R1 = c
MOV             R1, #0x38E38E39
//R1 = (argc * R1) >> 32
UMULL.W         argc, R1, argc, R1
//R1 = R1 >> 1
LSRS            R1, R1, #1
//R1 = (argc * c) >> 32 >> 1

arm-v8a:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
.text:00000000000006A8 main                                    ; DATA XREF: LOAD:0000000000000448↑o
.text:00000000000006A8                                         ; .got:main_ptr↓o
.text:00000000000006A8
.text:00000000000006A8 var_s0          =  0
.text:00000000000006A8
.text:00000000000006A8 argc = X0                               ; int
.text:00000000000006A8 argv = X1                               ; unsigned __int8 **
.text:00000000000006A8 ; __unwind {
.text:00000000000006A8                 STP             X29, X30, [SP,#-0x10+var_s0]!
.text:00000000000006AC                 MOV             X29, SP
.text:00000000000006B0                 MOV             W8, #0x38E38E39
.text:00000000000006B8                 UMULL           X8, W0, W8
.text:00000000000006BC                 ADRP            argc, #aArgc9@PAGE ; "argc / 9"
.text:00000000000006C0                 LSR             argv, X8, #33 ; '!'
.text:00000000000006C4                 ADD             X0, X0, #aArgc9@PAGEOFF ; "argc / 9"
.text:00000000000006C8                 BL              .printf
.text:00000000000006CC                 MOV             W0, WZR
.text:00000000000006D0                 LDP             X29, X30, [SP+var_s0],#0x10
.text:00000000000006D4                 RET
.text:00000000000006D4 ; } // starts at 6A8
.text:00000000000006D4 ; End of function main
1
2
3
4
5
6
//W8 = c
MOV             W8, #0x38E38E39
//X8 = argc * W8 //这里W0就是argc
UMULL           X8, W0, W8
//argv = X8 >> 33
LSR             argv, X8, #33

总结:

1
2
3
4
5
6
7
8
9
上述特征为:x / y = x * c >> 32 >> n
还原的话就看c,分为3种情况:
c为正数:y = 2^n / c
c为负数:y = 2^n / (2^32 - c)
c溢出:  y = 2^n / (2^32 + c)
以上述arm-v7a为例:
c = 0x38E38E39 = 954437177, 为正.
n = 32 + 1 = 33
则 y = 2^33 / 954437177 = 9
MagicNumber有进位

源代码:

1
printf("argc / 7", (unsigned int)argc / 7);

arm-v7a:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
.text:00002A00 main                                    ; DATA XREF: .text:000029BC↑o
.text:00002A00                                         ; .got:main_ptr↓o
.text:00002A00 argc = R0                               ; int
.text:00002A00 argv = R1                               ; unsigned __int8 **
.text:00002A00 ; __unwind {
.text:00002A00                 PUSH            {R7,LR}
.text:00002A02                 MOV             R7, SP
.text:00002A04                 MOVW            argv, #0x4925
.text:00002A08                 LDR             R2, =(aArgc7 - 0x2A16) ; "argc / 7"
.text:00002A0A                 MOVT            R1, #0x2492
.text:00002A0E                 UMULL.W         R1, R3, argc, R1
.text:00002A12                 ADD             R2, PC  ; "argc / 7"
.text:00002A14                 SUBS            argc, argc, R3
.text:00002A16                 ADD.W           R0, R3, R0,LSR#1
.text:00002A1A                 LSRS            R1, R0, #2
.text:00002A1C                 MOV             R0, R2  ; format
.text:00002A1E                 BLX             printf
.text:00002A22                 MOVS            R0, #0
.text:00002A24                 POP             {R7,PC}
.text:00002A24 ; End of function main
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
//R1 = 0x24924925 = c
MOVW            R1, #0x4925
MOVT            R1, #0x2492
//R3 = argc * R1 >> 32
UMULL.W         R1, R3, argc, R1
//argc = argc - R3
SUBS            argc, argc, R3
//argc = R3 + argc >> 1
ADD.W           argc, R3, argc,LSR#1
//R1 = argc >> 2
LSRS            R1, argc, #2
//R1 = (argc * c >> 32 + (argc - argc * c >> 32) >> 1) >> 2
这种形式的还原 y = 2^n / (2^32 + c) = 2^35 / (2^32 + 0x24924925) = 7

arm-v8a:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
.text:00000000000006A8 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:00000000000006A8                 EXPORT main
.text:00000000000006A8 main                                    ; DATA XREF: LOAD:0000000000000448↑o
.text:00000000000006A8                                         ; .got:main_ptr↓o
.text:00000000000006A8
.text:00000000000006A8 var_s0          =  0
.text:00000000000006A8
.text:00000000000006A8 argc = X0                               ; int
.text:00000000000006A8 argv = X1                               ; unsigned __int8 **
.text:00000000000006A8 ; __unwind {
.text:00000000000006A8                 STP             X29, X30, [SP,#-0x10+var_s0]!
.text:00000000000006AC                 MOV             X29, SP
.text:00000000000006B0                 MOV             W8, #0x24924925
.text:00000000000006B8                 UMULL           X8, W0, W8
.text:00000000000006BC                 LSR             X8, X8, #32 ; ' '
.text:00000000000006C0                 SUB             W9, W0, W8
.text:00000000000006C4                 ADD             W8, W8, W9,LSR#1
.text:00000000000006C8                 ADRP            argc, #aArgc7@PAGE ; "argc / 7"
.text:00000000000006CC                 LSR             W1, W8, #2
.text:00000000000006D0                 ADD             X0, X0, #aArgc7@PAGEOFF ; "argc / 7"
.text:00000000000006D4                 BL              .printf
.text:00000000000006D8                 MOV             W0, WZR
.text:00000000000006DC                 LDP             X29, X30, [SP+var_s0],#0x10
.text:00000000000006E0                 RET
.text:00000000000006E0 ; } // starts at 6A8
.text:00000000000006E0 ; End of function main
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
//w8 = c
MOV             W8, #0x24924925
//X8 = W0 * W8 = argc * W8
UMULL           X8, W0, W8
//X8 = X8 >> 32
LSR             X8, X8, #32
//W9 = W0 - W8
SUB             W9, W0, W8
//W8 = W8 + W9 >> 1
ADD             W8, W8, W9,LSR#1
//W1 = W8 >> 2
LSR             W1, W8, #2
//W1 = ((argc * c) >> 32 + (argc - ((argc * c) >> 32) >> 1) >> 2
//还原的方法同上

总结:

1
2
形如x / y =(x * c >> 32 + (x - x * c >> 32) >> n1) >> n2这种形式的
还原的话,y = 2^(32 + n1 + n2)/(2^32 + c)

有符号

除数为正2的幂

源代码:

1
printf("argc / 8", argc / 8);

arm-v7a:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
.text:00002A00 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:00002A00                 EXPORT main
.text:00002A00 main                                    ; DATA XREF: .text:000029BC↑o
.text:00002A00                                         ; .got:main_ptr↓o
.text:00002A00 argc = R0                               ; int
.text:00002A00 argv = R1                               ; unsigned __int8 **
.text:00002A00 ; __unwind {
.text:00002A00                 PUSH            {R7,LR}
.text:00002A02                 MOV             R7, SP
.text:00002A04                 LDR             R2, =(aArgc8 - 0x2A10) ; "argc / 8"
.text:00002A06                 ASRS            argv, argc, #0x1F
.text:00002A08                 ADD.W           argc, argc, R1,LSR#29
.text:00002A0C                 ADD             R2, PC  ; "argc / 8"
.text:00002A0E                 ASRS            R1, R0, #3
.text:00002A10                 MOV             R0, R2  ; format
.text:00002A12                 BLX             printf
.text:00002A16                 MOVS            R0, #0
.text:00002A18                 POP             {R7,PC}
.text:00002A18 ; End of function main
1
2
3
4
5
6
7
8
9
//R1 = argc >> 31
//如果argc为正数, R1 = 0, 否则 R1 = 0xFFFFFFFF
ASRS            R1, argc, #31
//argc = argc + R1 >> 29
//如果argc为正数, argc = argc, 否则 argc = argc + 7
ADD.W           argc, argc, R1,LSR#29
//R1 = argc >> 3
//如果argc为正数, R1 = argc >> 3, 否则 R1 = (argc + 7) >> 3
ASRS            R1, argc, #3

arm-v8a:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
.text:00000000000006A8 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:00000000000006A8                 EXPORT main
.text:00000000000006A8 main                                    ; DATA XREF: LOAD:0000000000000448↑o
.text:00000000000006A8                                         ; .got:main_ptr↓o
.text:00000000000006A8
.text:00000000000006A8 var_s0          =  0
.text:00000000000006A8
.text:00000000000006A8 argc = X0                               ; int
.text:00000000000006A8 argv = X1                               ; unsigned __int8 **
.text:00000000000006A8 ; __unwind {
.text:00000000000006A8                 STP             X29, X30, [SP,#-0x10+var_s0]!
.text:00000000000006AC                 MOV             X29, SP
.text:00000000000006B0                 ADD             W8, W0, #7
.text:00000000000006B4                 CMP             W0, #0
.text:00000000000006B8                 CSEL            W8, W8, W0, LT
.text:00000000000006BC                 ADRP            argc, #aArgc8@PAGE ; "argc / 8"
.text:00000000000006C0                 ASR             W1, W8, #3
.text:00000000000006C4                 ADD             X0, X0, #aArgc8@PAGEOFF ; "argc / 8"
.text:00000000000006C8                 BL              .printf
.text:00000000000006CC                 MOV             W0, WZR
.text:00000000000006D0                 LDP             X29, X30, [SP+var_s0],#0x10
.text:00000000000006D4                 RET
.text:00000000000006D4 ; } // starts at 6A8
.text:00000000000006D4 ; End of function main
1
2
3
4
5
6
7
//W8 = argc + 7
ADD             W8, argc, #7
CMP             argc, #0
//如果argc < 0, W8 = argc + 7, 否则W8 = argc
CSEL            W8, W8, argc, LT
//W1 = W8 >> 3
ASR             W1, W8, #3

总结:

1
2
3
x > 0, x / y = x >> n
x < 0, x / y = (x + 2 ^n - 1) >> n
这种还原的话就是,y = 2^n
除数为正非2的幂
MagicNumber为正

源代码:

1
printf("argc / 9", argc / 9);

arm-v7a:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
.text:00002A00 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:00002A00                 EXPORT main
.text:00002A00 main                                    ; DATA XREF: .text:000029BC↑o
.text:00002A00                                         ; .got:main_ptr↓o
.text:00002A00 argc = R0                               ; int
.text:00002A00 argv = R1                               ; unsigned __int8 **
.text:00002A00 ; __unwind {
.text:00002A00                 PUSH            {R7,LR}
.text:00002A02                 MOV             R7, SP
.text:00002A04                 MOV             R1, #0x38E38E39
.text:00002A0C                 SMMUL.W         R1, argc, R1
.text:00002A10                 LDR             argc, =(aArgc9 - 0x2A16) ; "argc / 9"
.text:00002A12                 ADD             R0, PC  ; "argc / 9"
.text:00002A14                 ASRS            R2, R1, #1
.text:00002A16                 ADD.W           R1, R2, R1,LSR#31
.text:00002A1A                 BLX             printf
.text:00002A1E                 MOVS            R0, #0
.text:00002A20                 POP             {R7,PC}
.text:00002A20 ; End of function main
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
//R1 = c
MOV             R1, #0x38E38E39
//R1 = argc * R1 >> 32
SMMUL.W         R1, argc, R1
//R2 = R1 >> 1
ASRS            R2, R1, #1
//R1 = R2 + R1 >> 31
ADD.W           R1, R2, R1,LSR#31
//R1 = argc * c >> 32 >> 1 + argc * c >> 63
//argc >= 0, argc * c >> 32 >> n
//argc < 0, argc * c >> 32 >> n + 1

arm-v8a:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
.text:00000000000006A8 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:00000000000006A8                 EXPORT main
.text:00000000000006A8 main                                    ; DATA XREF: LOAD:0000000000000448↑o
.text:00000000000006A8                                         ; .got:main_ptr↓o
.text:00000000000006A8
.text:00000000000006A8 var_s0          =  0
.text:00000000000006A8
.text:00000000000006A8 argc = X0                               ; int
.text:00000000000006A8 argv = X1                               ; unsigned __int8 **
.text:00000000000006A8 ; __unwind {
.text:00000000000006A8                 STP             X29, X30, [SP,#-0x10+var_s0]!
.text:00000000000006AC                 MOV             X29, SP
.text:00000000000006B0                 MOV             W8, #0x38E38E39
.text:00000000000006B8                 SMULL           X8, W0, W8
.text:00000000000006BC                 LSR             X9, X8, #0x3F ; '?'
.text:00000000000006C0                 ASR             X8, X8, #0x21 ; '!'
.text:00000000000006C4                 ADRP            argc, #aArgc9@PAGE ; "argc / 9"
.text:00000000000006C8                 ADD             W1, W8, W9
.text:00000000000006CC                 ADD             X0, X0, #aArgc9@PAGEOFF ; "argc / 9"
.text:00000000000006D0                 BL              .printf
.text:00000000000006D4                 MOV             W0, WZR
.text:00000000000006D8                 LDP             X29, X30, [SP+var_s0],#0x10
.text:00000000000006DC                 RET
.text:00000000000006DC ; } // starts at 6A8
.text:00000000000006DC ; End of function main
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
//W8 = c
MOV             W8, #0x38E38E39
//X8 = argc * W8
SMULL           X8, argc, W8
//X9 = X8 >> 63
LSR             X9, X8, #63
//X8 = X8 >> 33
ASR             X8, X8, #33
//W1 = W8 + W9
ADD             W1, W8, W9
//W1 = argc * c >> 33 + argc * c >> 63
//argc >= 0, argc * c >> 32 >> n
//argc < 0,  argc * c >> 32 >> n + 1

总结:

1
2
3
4
c为正:
x >= 0, x * c >> 32 >> n
x < 0,  x * c >> 32 >> n + 1
还原的时候, y = 2^(32 + n) / c
MagicNumber为负

源代码:

1
printf("argc / 7", argc / 7);

arm-v7a:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
.text:00002A00 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:00002A00                 EXPORT main
.text:00002A00 main                                    ; DATA XREF: .text:000029BC↑o
.text:00002A00                                         ; .got:main_ptr↓o
.text:00002A00 argc = R0                               ; int
.text:00002A00 argv = R1                               ; unsigned __int8 **
.text:00002A00 ; __unwind {
.text:00002A00                 PUSH            {R7,LR}
.text:00002A02                 MOV             R7, SP
.text:00002A04                 MOV             R1, #0x92492493
.text:00002A0C                 SMMLA.W         R1, R1, argc, argc
.text:00002A10                 LDR             argc, =(aArgc7 - 0x2A16) ; "argc / 7"
.text:00002A12                 ADD             R0, PC  ; "argc / 7"
.text:00002A14                 ASRS            R2, R1, #2
.text:00002A16                 ADD.W           R1, R2, R1,LSR#31
.text:00002A1A                 BLX             printf
.text:00002A1E                 MOVS            R0, #0
.text:00002A20                 POP             {R7,PC}
.text:00002A20 ; End of function main
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
//R1 = c
MOV             R1, #0x92492493
//R1 = R1 * argc >> 32 + argc
SMMLA.W         R1, R1, argc, argc
//R2 = R1 >> 2
ASRS            R2, R1, #2
//R1 = R2 + R1 >> 31
ADD.W           R1, R2, R1,LSR#31
//R1 = (c * argc >> 32 + argc) >> 2 + (c * argc >> 32 + argc) >> 31
//argc >= 0, (c * argc >> 32 + argc) >> 2 + 1
//argc < 0,  (c * argc >> 32 + argc) >> 2

arm-v8a:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
.text:00000000000006A8 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:00000000000006A8                 EXPORT main
.text:00000000000006A8 main                                    ; DATA XREF: LOAD:0000000000000448↑o
.text:00000000000006A8                                         ; .got:main_ptr↓o
.text:00000000000006A8
.text:00000000000006A8 var_s0          =  0
.text:00000000000006A8
.text:00000000000006A8 argc = X0                               ; int
.text:00000000000006A8 argv = X1                               ; unsigned __int8 **
.text:00000000000006A8 ; __unwind {
.text:00000000000006A8                 STP             X29, X30, [SP,#-0x10+var_s0]!
.text:00000000000006AC                 MOV             X29, SP
.text:00000000000006B0                 MOV             W8, #0x92492493
.text:00000000000006B8                 SMULL           X8, W0, W8
.text:00000000000006BC                 LSR             X8, X8, #0x20 ; ' '
.text:00000000000006C0                 ADD             W8, W8, W0
.text:00000000000006C4                 ASR             W9, W8, #2
.text:00000000000006C8                 ADRP            argc, #aArgc7@PAGE ; "argc / 7"
.text:00000000000006CC                 ADD             W1, W9, W8,LSR#31
.text:00000000000006D0                 ADD             X0, X0, #aArgc7@PAGEOFF ; "argc / 7"
.text:00000000000006D4                 BL              .printf
.text:00000000000006D8                 MOV             W0, WZR
.text:00000000000006DC                 LDP             X29, X30, [SP+var_s0],#0x10
.text:00000000000006E0                 RET
.text:00000000000006E0 ; } // starts at 6A8
.text:00000000000006E0 ; End of function main
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
//W8 = c
MOV             W8, #0x92492493
//X8 = argc * c
SMULL           X8, argc, W8
//X8 = X8 >> 32
LSR             X8, X8, #32
//W8 = W8 + argc
ADD             W8, W8, argc
//W9 = W8 >> 2
ASR             W9, W8, #2
//W1 = W9 + W8 >> 31
ADD             W1, W9, W8,LSR#31
//W1 = (argc * c >> 32 + argc) >> 2 + (argc * c >> 32 + argc) >> 31
//argc >= 0, (c * argc >> 32 + argc) >> 2 + 1
//argc < 0,  (c * argc >> 32 + argc) >> 2

总结:

1
2
3
4
c为负:
x >= 0, (c * x >> 32 + x) >> n + 1
x < 0,  (c * x >> 32 + x) >> n
还原的时候,y = 2^(32 + n) / c
除数为负2的幂

源代码:

1
printf("argc / -8", argc / -8);

arm-v7a:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
.text:00002A00 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:00002A00                 EXPORT main
.text:00002A00 main                                    ; DATA XREF: .text:000029BC↑o
.text:00002A00                                         ; .got:main_ptr↓o
.text:00002A00 argc = R0                               ; int
.text:00002A00 argv = R1                               ; unsigned __int8 **
.text:00002A00 ; __unwind {
.text:00002A00                 PUSH            {R7,LR}
.text:00002A02                 MOV             R7, SP
.text:00002A04                 LDR             R2, =(aArgc8 - 0x2A12) ; "argc / -8"
.text:00002A06                 ASRS            argv, argc, #0x1F
.text:00002A08                 ADD.W           argc, argc, R1,LSR#29
.text:00002A0C                 MOVS            R1, #0
.text:00002A0E                 ADD             R2, PC  ; "argc / -8"
.text:00002A10                 SUB.W           R1, R1, R0,ASR#3
.text:00002A14                 MOV             R0, R2  ; format
.text:00002A16                 BLX             printf
.text:00002A1A                 MOVS            R0, #0
.text:00002A1C                 POP             {R7,PC}
.text:00002A1C ; End of function main
1
2
3
4
5
6
7
8
//R1 = argc >> 31
ASRS            R1, argc, #31
//argc = argc + R1 >> 29
ADD.W           argc, argc, R1,LSR#29
//R1 = 0
MOVS            R1, #0
// R1 = 0 - R0 >> 3
SUB.W           R1, R1, R0,ASR#3

arm-v8a:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
.text:00000000000006A8 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:00000000000006A8                 EXPORT main
.text:00000000000006A8 main                                    ; DATA XREF: LOAD:0000000000000448↑o
.text:00000000000006A8                                         ; .got:main_ptr↓o
.text:00000000000006A8
.text:00000000000006A8 var_s0          =  0
.text:00000000000006A8
.text:00000000000006A8 argc = X0                               ; int
.text:00000000000006A8 argv = X1                               ; unsigned __int8 **
.text:00000000000006A8 ; __unwind {
.text:00000000000006A8                 STP             X29, X30, [SP,#-0x10+var_s0]!
.text:00000000000006AC                 MOV             X29, SP
.text:00000000000006B0                 ADD             W8, W0, #7
.text:00000000000006B4                 CMP             W0, #0
.text:00000000000006B8                 CSEL            W8, W8, W0, LT
.text:00000000000006BC                 ADRP            argc, #aArgc8@PAGE ; "argc / -8"
.text:00000000000006C0                 NEG             W1, W8,ASR#3
.text:00000000000006C4                 ADD             X0, X0, #aArgc8@PAGEOFF ; "argc / -8"
.text:00000000000006C8                 BL              .printf
.text:00000000000006CC                 MOV             W0, WZR
.text:00000000000006D0                 LDP             X29, X30, [SP+var_s0],#0x10
.text:00000000000006D4                 RET
.text:00000000000006D4 ; } // starts at 6A8
.text:00000000000006D4 ; End of function main
1
2
3
4
5
6
7
//W8 = argc + 7
ADD             W8, argc, #7
CMP             argc, #0
//如果argc < 0, W8 = argc + 7, 否则W8 = argc
CSEL            W8, W8, argc, LT
//W1 = -W8 >> 3
NEG             W1, W8,ASR#3

总结:

1
除数为负的2的幂的情况,跟除数为正的2的幂的情况相同,只不过加了一个负号
除数为负非2的幂
MagicNumber为正

源代码:

1
printf("argc / -7", argc / -7);

arm-v7a:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
.text:00002A00 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:00002A00                 EXPORT main
.text:00002A00 main                                    ; DATA XREF: .text:000029BC↑o
.text:00002A00                                         ; .got:main_ptr↓o
.text:00002A00 argc = R0                               ; int
.text:00002A00 argv = R1                               ; unsigned __int8 **
.text:00002A00 ; __unwind {
.text:00002A00                 PUSH            {R7,LR}
.text:00002A02                 MOV             R7, SP
.text:00002A04                 MOVW            argv, #0xDB6D
.text:00002A08                 LDR             R2, =(aArgc7 - 0x2A16) ; "argc / -7"
.text:00002A0A                 MOVT            R1, #0x6DB6
.text:00002A0E                 SMMUL.W         R1, argc, R1
.text:00002A12                 ADD             R2, PC  ; "argc / -7"
.text:00002A14                 SUBS            argc, R1, argc
.text:00002A16                 ASRS            R1, R0, #2
.text:00002A18                 ADD.W           R1, R1, R0,LSR#31
.text:00002A1C                 MOV             R0, R2  ; format
.text:00002A1E                 BLX             printf
.text:00002A22                 MOVS            R0, #0
.text:00002A24                 POP             {R7,PC}
.text:00002A24 ; End of function main
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
//R1 = 0x6DB6DB6D = c
MOVW            R1, #0xDB6D
MOVT            R1, #0x6DB6
//R1 = argc * R1 >> 32
SMMUL.W         R1, argc, R1
//argc = R1 - argc
SUBS            argc, R1, argc
//R1 = argc >> 2
ASRS            R1, argc, #2
//R1 = R1 + argc >> 31
ADD.W           R1, R1, argc,LSR#31
//R1 = (argc * c >> 32 - argc) >> 2 + (argc * c >> 32 - argc) >> 31
//argc >= 0, (argc * c >> 32 - argc) >> 2
//argc <  0, (argc * c >> 32 - argc) >> 2 + 1

arm-v8a:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
.text:00000000000006A8 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:00000000000006A8                 EXPORT main
.text:00000000000006A8 main                                    ; DATA XREF: LOAD:0000000000000448↑o
.text:00000000000006A8                                         ; .got:main_ptr↓o
.text:00000000000006A8
.text:00000000000006A8 var_s0          =  0
.text:00000000000006A8
.text:00000000000006A8 argc = X0                               ; int
.text:00000000000006A8 argv = X1                               ; unsigned __int8 **
.text:00000000000006A8 ; __unwind {
.text:00000000000006A8                 STP             X29, X30, [SP,#-0x10+var_s0]!
.text:00000000000006AC                 MOV             X29, SP
.text:00000000000006B0                 MOV             W8, #0x6DB6DB6D
.text:00000000000006B8                 SMULL           X8, W0, W8
.text:00000000000006BC                 LSR             X8, X8, #0x20 ; ' '
.text:00000000000006C0                 SUB             W8, W8, W0
.text:00000000000006C4                 ASR             W9, W8, #2
.text:00000000000006C8                 ADRP            argc, #aArgc7@PAGE ; "argc / -7"
.text:00000000000006CC                 ADD             W1, W9, W8,LSR#31
.text:00000000000006D0                 ADD             X0, X0, #aArgc7@PAGEOFF ; "argc / -7"
.text:00000000000006D4                 BL              .printf
.text:00000000000006D8                 MOV             W0, WZR
.text:00000000000006DC                 LDP             X29, X30, [SP+var_s0],#0x10
.text:00000000000006E0                 RET
.text:00000000000006E0 ; } // starts at 6A8
.text:00000000000006E0 ; End of function main
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
//W8 = c
MOV             W8, #0x6DB6DB6D
//X8 = argc * W8
SMULL           X8, argc, W8
//X8 = X8 >> 32
LSR             X8, X8, #32
//W8 = W8 - argc
SUB             W8, W8, argc
//W9 = W8 >> 2
ASR             W9, W8, #2
//W1 = W9 + W8 >> 31
ADD             W1, W9, W8,LSR#31
//W1 = (argc * c >> 32 - argc) >> 2 + (argc * c >> 32 - argc) >> 31
//argc >= 0, (argc * c >> 32 - argc) >> 2
//argc <  0, (argc * c >> 32 - argc) >> 2 + 1

总结:

1
2
3
4
c为正:
x >= 0, (x * c >> 32 - x) >> 2
x <  0, (x * c >> 32 - x) >> 2 + 1
还原的时候, y = -2^(32 + n) / (2^32 - c)
MagicNumber为负

源代码:

1
printf("argc / -9", argc / -9);

arm-v7a:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
.text:00002A00 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:00002A00                 EXPORT main
.text:00002A00 main                                    ; DATA XREF: .text:000029BC↑o
.text:00002A00                                         ; .got:main_ptr↓o
.text:00002A00 argc = R0                               ; int
.text:00002A00 argv = R1                               ; unsigned __int8 **
.text:00002A00 ; __unwind {
.text:00002A00                 PUSH            {R7,LR}
.text:00002A02                 MOV             R7, SP
.text:00002A04                 MOV             R1, #0xC71C71C7
.text:00002A0C                 SMMUL.W         R1, argc, R1
.text:00002A10                 LDR             argc, =(aArgc9 - 0x2A16) ; "argc / -9"
.text:00002A12                 ADD             R0, PC  ; "argc / -9"
.text:00002A14                 ASRS            R2, R1, #1
.text:00002A16                 ADD.W           R1, R2, R1,LSR#31 ; n1
.text:00002A1A                 BLX             printf
.text:00002A1E                 MOVS            R0, #0
.text:00002A20                 POP             {R7,PC}
.text:00002A20 ; End of function main
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
//R1 = c
MOV             R1, #0xC71C71C7
//R1 = argc * R1 >> 32
SMMUL.W         R1, argc, R1
//R2 = R1 >> 1
ASRS            R2, R1, #1
//R1 = R2 + R1 >> 31
ADD.W           R1, R2, R1,LSR#31
//R1 = argc * c >> 32 >> 1 + argc * c >> 63
//argc >= 0, argc * c >> 32 >> n + 1
//argc < 0, argc * c >> 32 >> n

arm-v8a:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
.text:00000000000006A8 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:00000000000006A8                 EXPORT main
.text:00000000000006A8 main                                    ; DATA XREF: LOAD:0000000000000448↑o
.text:00000000000006A8                                         ; .got:main_ptr↓o
.text:00000000000006A8
.text:00000000000006A8 var_s0          =  0
.text:00000000000006A8
.text:00000000000006A8 argc = X0                               ; int
.text:00000000000006A8 argv = X1                               ; unsigned __int8 **
.text:00000000000006A8 ; __unwind {
.text:00000000000006A8                 STP             X29, X30, [SP,#-0x10+var_s0]!
.text:00000000000006AC                 MOV             X29, SP
.text:00000000000006B0                 MOV             W8, #0xC71C71C7
.text:00000000000006B8                 SMULL           X8, W0, W8
.text:00000000000006BC                 LSR             X9, X8, #63 ; '?'
.text:00000000000006C0                 ASR             X8, X8, #33 ; '!'
.text:00000000000006C4                 ADRP            argc, #aArgc9@PAGE ; "argc / -9"
.text:00000000000006C8                 ADD             W1, W8, W9 ; n1
.text:00000000000006CC                 ADD             X0, X0, #aArgc9@PAGEOFF ; "argc / -9"
.text:00000000000006D0                 BL              .printf
.text:00000000000006D4                 MOV             W0, WZR
.text:00000000000006D8                 LDP             X29, X30, [SP+var_s0],#0x10
.text:00000000000006DC                 RET
.text:00000000000006DC ; } // starts at 6A8
.text:00000000000006DC ; End of function main
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
//W8 = c
MOV             W8, #0xC71C71C7
//X8 = argc * W8
SMULL           X8, argc, W8
//X9 = X8 >> 63
LSR             X9, X8, #63
//X8 = X8 >> 33
ASR             X8, X8, #33
//W1 = W8 + W9
ADD             W1, W8, W9
//W1 = argc * c >> 33 + argc * c >> 63
//argc >= 0, argc * c >> 32 >> n +1
//argc < 0,  argc * c >> 32 >> n

总结:

1
2
3
4
c为负:
x >= 0, x * c >> 32 >> n + 1
x < 0,  x * c >> 32 >> n
还原的时候, y = -2^(32 + n) / (2^32 - c)

取模

无符号

除数为2的幂

源代码:

1
printf("argc % 8", (unsigned int)argc % 8);

arm-v7a:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
.text:00002A00 main                                    ; DATA XREF: .text:000029BC↑o
.text:00002A00                                         ; .got:main_ptr↓o
.text:00002A00 argc = R0                               ; int
.text:00002A00 argv = R1                               ; unsigned __int8 **
.text:00002A00 ; __unwind {
.text:00002A00                 PUSH            {R7,LR}
.text:00002A02                 MOV             R7, SP
.text:00002A04                 LDR             R2, =(aArgc8 - 0x2A0E) ; "argc % 8"
.text:00002A06                 AND.W          argv, argc, #7
.text:00002A0A                 ADD             R2, PC  ; "argc % 8"
.text:00002A0C                 MOV             argc, R2 ; format
.text:00002A0E                 BLX             printf
.text:00002A12                 MOVS            R0, #0
.text:00002A14                 POP             {R7,PC}
.text:00002A14 ; End of function main
1
2
//R1 = argc & 7
AND.W           R1, argc, #7

总结:

1
x % y = x & (2^ - 1)
除数为非2的幂

源代码:

1
printf("argc % 9", (unsigned int)argc % 9);

arm-v7a:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
.text:00002A00 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:00002A00                 EXPORT main
.text:00002A00 main                                    ; DATA XREF: .text:000029BC↑o
.text:00002A00                                         ; .got:main_ptr↓o
.text:00002A00 argc = R0                               ; int
.text:00002A00 argv = R1                               ; unsigned __int8 **
.text:00002A00 ; __unwind {
.text:00002A00                 PUSH            {R7,LR}
.text:00002A02                 MOV             R7, SP
.text:00002A04                 MOVW            argv, #0x8E39
.text:00002A08                 LDR             R2, =(aArgc9 - 0x2A16) ; "argc % 9"
.text:00002A0A                 MOVT            R1, #0x38E3
.text:00002A0E                 UMULL.W         R1, R3, argc, R1
.text:00002A12                 ADD             R2, PC  ; "argc % 9"
.text:00002A14                 LSRS            R1, R3, #1
.text:00002A16                 ADD.W           R1, R1, R1,LSL#3
.text:00002A1A                 SUBS            R1, argc, R1
.text:00002A1C                 MOV             argc, R2 ; format
.text:00002A1E                 BLX             printf
.text:00002A22                 MOVS            R0, #0
.text:00002A24                 POP             {R7,PC}
.text:00002A24 ; End of function main
1
2
3
4
5
6
7
8
MOVW            R1, #0x8E39
MOVT            R1, #0x38E3
UMULL.W         R1, R3, argc, R1
LSRS            R1, R3, #1
//上面是除法运算,结果在R1中
ADD.W           R1, R1, R1,LSL#3
SUBS            R1, argc, R1
//余数 = 被除数 - 除数 * 

有符号

除数为2的幂

源代码:

1
printf("argc % 8", argc % 8);

arm-v7a:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
.text:00002A00 main                                    ; DATA XREF: .text:000029BC↑o
.text:00002A00                                         ; .got:main_ptr↓o
.text:00002A00 argc = R0                               ; int
.text:00002A00 argv = R1                               ; unsigned __int8 **
.text:00002A00 ; __unwind {
.text:00002A00                 PUSH            {R7,LR}
.text:00002A02                 MOV             R7, SP
.text:00002A04                 LDR             R2, =(aArgc8 - 0x2A14) ; "argc % 8"
.text:00002A06                 ASRS            argv, argc, #0x1F
.text:00002A08                 ADD.W           R1, argc, R1,LSR#29
.text:00002A0C                 BIC.W           R1, R1, #7
.text:00002A10                 ADD             R2, PC  ; "argc % 8"
.text:00002A12                 SUBS            R1, argc, R1
.text:00002A14                 MOV             argc, R2 ; format
.text:00002A16                 BLX             printf
.text:00002A1A                 MOVS            R0, #0
.text:00002A1C                 POP             {R7,PC}
.text:00002A1C ; End of function main
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
//R1 = argc >> 31
ASRS            R1, argc, #31
//R1 = argc + R1 >> 29
//如果argc >= 0, R1 = argc
//如果argc <  0, R1 = argc + 7
ADD.W           R1, argc, R1,LSR#29
//R1 = R1 & ~7
BIC.W           R1, R1, #7
//R1 = argc - R1
SUBS            R1, argc, R1

总结:

1
2
x >= 0,x % y = x - x & ~(2^n - 1)
x <  0,x % y = x - (x + 2^n - 1) &~(2^n - 1)
除数为非2的幂

源代码:

1
printf("argc % 9", argc % 9);

arm-v7a:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
.text:00002A00 main                                    ; DATA XREF: .text:000029BC↑o
.text:00002A00                                         ; .got:main_ptr↓o
.text:00002A00 argc = R0                               ; int
.text:00002A00 argv = R1                               ; unsigned __int8 **
.text:00002A00 ; __unwind {
.text:00002A00                 PUSH            {R7,LR}
.text:00002A02                 MOV             R7, SP
.text:00002A04                 MOVW            argv, #0x8E39
.text:00002A08                 LDR             R2, =(aArgc9 - 0x2A16) ; "argc % 9"
.text:00002A0A                 MOVT            R1, #0x38E3
.text:00002A0E                 SMMUL.W         R1, argc, R1
.text:00002A12                 ADD             R2, PC  ; "argc % 9"
.text:00002A14                 ASRS            R3, R1, #1
.text:00002A16                 ADD.W           R1, R3, R1,LSR#31
.text:00002A1A                 ADD.W           R1, R1, R1,LSL#3
.text:00002A1E                 SUBS            R1, argc, R1
.text:00002A20                 MOV             argc, R2 ; format
.text:00002A22                 BLX             printf
.text:00002A26                 MOVS            R0, #0
.text:00002A28                 POP             {R7,PC}
.text:00002A28 ; End of function main
1
2
3
4
5
6
7
8
9
MOVW            argv, #0x8E39
MOVT            R1, #0x38E3
SMMUL.W         R1, argc, R1
ASRS            R3, R1, #1
ADD.W           R1, R3, R1,LSR#31
//上面是除法运算, R1为商
ADD.W           R1, R1, R1,LSL#3
SUBS            R1, argc, R1
//余数 = 被除数 -  * 除数

分支

if

源代码:

1
2
3
4
5
if (argc > 0){
       printf("argc > 0");
   } else{
       puts("argc <= 0");
   }

arm-v7a:

if

while

源代码:

1
2
3
4
while (argc < 10) {
       printf("%d\n", argc);
       argc++;
   }

arm-v7a:

while

do-while

源代码:

1
2
3
4
do {
    printf("%d\n", argc);
    argc++;
} while (argc < 10);

arm-v7a:

dowhile

Switch-case

这里只讨论做表的情况.

源代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
switch (argc) {
    case 1:{
        printf("%d", 1);
        break;
    }
    case 3:{
        puts("3");
        break;
    }
    case 5:{
        printf("%d", 5);
        break;
    }
    case 9:{
        printf("9");
        break;
    }
}

arm-v7a:

switch

函数

这一部分跟x86相差还是挺大的.

整型传参

源代码:

1
2
3
4
5
6
7
8
9
int add1(int n1, int n2, int n3, int n4, int n5, int n6, int n7, int n8, int n9) {
    return n1 + n2 + n3 + n4 + n5 + n6 + n7 + n8 + n9;
}

int main(int argc, char *argv[]) {
    int n = add1(1, 2, 3, 4, 5, 6, 7, 8, 9);
    printf("%d\n", n);
    return 0;
}

arm-v7a:

整型传参v7

从上面可以看到,前4个整型参数放在寄存器R0-R3中,后面的参数就入栈了,整型返回值放在R0中.

arm-v8a:

整型传参v8

从上面可以看到,前8个整型参数放在寄存器X0-X7中,后面的参数就入栈了,整型返回值放在X0中.

浮点传参

源代码:

1
2
3
4
5
6
7
8
float add2(float f1, float f2, float f3, float f4, float f5, float f6, float f7, float f8, float f9) {
    return f1 + f2 + f3 + f4 + f5 + f6 + f7 + f8 + f9;
}
int main(int argc, char *argv[]) {
    float f = add2(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0);
    printf("%f\n", f);
    return 0;
}

arm-v7a:

浮点传参v7

从上面可以看到,浮点传参跟整型传参没有区别,前4个参数放R0-R3,后面的参数入栈,浮点返回值放在R0中.

arm-v8a:

浮点传参v8

从上面可以看到,前8个浮点参数,放浮点寄存器S0-S7,后面的浮点参数入栈,浮点返回值放在S0中.

混合传参

源代码:

1
2
3
4
5
6
7
8
long long add3(int n1, float f2, int n3, float f4, int n5, float f6, int n7, float f8, int n9) {
    return n1 + f2 + n3 + f4 + n5 + f6 + n7 + f8 + n9;
}
int main(int argc, char *argv[]) {
    long long l = add3(1, 2.0, 3, 4.0, 5, 6.0, 7, 8.0, 9);
    printf("%ld\n", l);
    return 0;
}

arm-v7a:

混合传参v7

从上面可以看到,混合传参对32位没有影响,前4个参数放R0-R3中,后面的参数入栈,长整型的返回值放在R1 .

arm-v8a:

混合传参v8

从上面可以看到,对于混合传参,64位的处理方式还是挺特别的,将整型参数放在X0-X7中,浮点参数放在S0-S7中,单从传参来说,没有办法区分谁是第一个参数,谁是第二个参数,除非有符号.

注意的小细节

源代码:

1
2
3
4
5
6
7
8
long long add4(int n1, long long n2, float f3){
    return n1 + n2 + f3;
}
int main(int argc, char *argv[]) {
    long long l = add4(1, 2, 3.0);
    printf("%ld\n", l);
    return 0;
}

arm-v7a:

函数注意的小细节

本例中,long long add4(int n1, long long n2, float f3); 按理来说n1放R0,n2放R2, R1, f3放R3. 但从上面的汇编代码来看,并没有用到寄存器R1, 也就是说64位整型,低32位放的应该是2的幂下标的寄存器,如R1 R0, R3 R2. 而不是像R2 R1这种的.

变量

全局变量

源代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
int g_n1 = 100;
int g_n2;
int g_n3 = fun1(10, 20);
__attribute__ ((constructor)) void myload(){
    printf("myload\n");
    g_n2 = 200;
}

__attribute__ ((destructor)) void myunload(){
    printf("myunload\n");
}

int main(int argc, char *argv[]) {
    printf("%d %d %d\n", g_n1, g_n2, g_n3);
    return 0;
}

总结:

变量1

全局变量初始化以及初始化函数在.init_array这个区段中. 反初始化函数在.fini_array这个区段中.

静态局部变量

源代码:

1
2
3
4
5
6
7
8
9
void showStatic(int n) {
    static int nStatic = n;
   printf("%d\n", nStatic);
}

int main(int argc, char *argv[]) {
    showStatic(argc);
    return 0;
}

总结:

变量2

这部分跟x86一样,就不细述了.

数组

一维数组

源代码:

1
2
3
4
5
int main(int argc, char *argv[]) {
    int ary[5] = {1, 2, 3, 4, 5};
    printf("%d %d", ary[1], ary[argc]);
    return 0;
}

总结:

数组1

1
2
3
假设数组为ary[n]
ary[x]寻址:
数组首地址 + x * sizeof(type)

二维数组

源代码:

1
2
3
4
5
6
7
8
int main(int argc, char *argv[]) {
    int ary[2][3] = {1, 2, 3, 4, 5, 6};
    int x = 0;
    int y = 0;
    scanf("%d", &x, &y);
    printf("%d", ary[x][y]);
    return 0;
}

总结:

数组2

1
2
3
假设数组为ary[M][N]
ary[x][y]寻址:
ary + x * sizeof(type[N]) + y * sizeof(type)

如果没有虚函数,类和结构体是没办法区分的.

this指针

源代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
class Person{
public:
    Person(){
        m_nAge = 10;
        m_nHeight = 20;
    };
    ~Person(){};
    int GetAge(){return m_nAge;}
    int GetHeight(){return m_nHeight;}
private:
    int m_nAge;
    int m_nHeight;
};

int main(int argc, char *argv[]) {
    Person person;
    return 0;
}

总结:

this指针

1
32位this指针放在R0,64位this指针放在X0

对象作为参数

源代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Person{
public:
    Person(){
        m_nAge = 10;
        m_nHeight = 20;
        m_nWeight = 30;
    };
    ~Person(){};
public:
    int m_nAge;
    int m_nHeight;
    int m_nWeight;
};

void showPerson(Person person){
    person.m_nAge = 100;
    printf("%d %d %d\n", person.m_nAge, person.m_nHeight, person.m_nWeight);
}

int main(int argc, char *argv[]) {
    Person person;
    showPerson(person);
    return 0;
}

总结:

对象作为参数

1
将原类中的成员拷贝到一块内存区域,然后将该内存区域的首地址传进去

返回对象

源代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Person{
public:
    Person(){
        m_nAge = 10;
        m_nHeight = 20;
        m_nWeight = 30;
    };
    ~Person(){};
public:
    int m_nAge;
    int m_nHeight;
    int m_nWeight;
};

Person getPerson(){
    Person person;
    person.m_nAge = 100;
    person.m_nHeight = 200;
    person.m_nWeight = 300;
    return  person;

}

int main(int argc, char *argv[]) {
    Person person = getPerson();
    printf("%d %d %d\n", person.m_nAge, person.m_nHeight, person.m_nWeight);
    return 0;
}

总结:

返回对象

1
多传一个存放类对象的地址进去

构造函数

源代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
class Person{
public:
    Person(){
        puts("Person()");
    };
    ~Person(){};
    virtual int getAge(){return m_nAge;}
    virtual int getHeight(){return m_nHeight;}
public:
    int m_nAge;
    int m_nHeight;
};

int main(int argc, char *argv[]) {
    Person person;
    return 0;
}

总结:

构造函数

1
2
3
类有虚函数,才可以识别构造函数
在构造函数中很明显的特征就是要填虚表地址,
还有一些特征比如说作用域内第一次调用,返回this指针

虚析构

源代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class Person{
public:
    Person(){
        puts("Person()");
    };
    virtual ~Person(){};
    virtual int getAge(){return m_nAge;}
    virtual int getHeight(){return m_nHeight;}
public:
    int m_nAge;
    int m_nHeight;
};

int main(int argc, char *argv[]) {
    Person *p = new Person;
    p->~Person();//这种没有释放空间
    delete p;  //这种要释放空间
    return 0;
}

总结:

虚析构1

虚析构2

1
2
3
VS编译的x86需要传参来判断是不是需要释放空间,
而Clang编译的Arm却不是这样的,它生成了两个析构函数,一个释放空间,一个没有释放空间.
这样的话,析构就不需要传参了.

单重继承

源代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class BaseHuman {
public:
    BaseHuman() {
        m_nBase = 1000;
    }

    int m_nBase;
};

class Person : public BaseHuman {
public:
    Person() {
        puts("Person()");
    };

    virtual ~Person() {};
    virtual int getAge() { return m_nAge; }
    virtual int getHeight() { return m_nHeight; }

public:
    int m_nAge;
    int m_nHeight;
};

int main(int argc, char *argv[]) {
    Person person;
    return 0;
}

总结:

单重继承

1
2
父类构造在填虚表之前,
成员对象构造在填虚表之后.

相关内容

0%