这部分内容跟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: 00002 A00 main ; DATA XREF: .text:000029BC↑o
.text: 00002 A00 ; .got:main_ptr↓o
.text: 00002 A00 argc = R0 ; int
.text: 00002 A00 argv = R1 ; unsigned __int8 **
.text: 00002 A00 ; __unwind {
.text: 00002 A00 PUSH { R7 , LR }
.text: 00002 A02 MOV R7 , SP
.text: 00002 A04 LDR argc , = ( aN1D - 0x2A0C ) ; "n1 = %d\n"
.text: 00002 A06 MOVS argv , #3
.text: 00002 A08 ADD R0 , PC ; "n1 = %d\n"
.text: 00002 A0A BLX printf
.text: 00002 A0E MOVS R0 , #0
.text: 00002 A10 POP { R7 , PC }
.text: 00002 A10 ; End of function main
arm-v8a:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
.text: 00002 A00 main ; DATA XREF: .text:000029BC↑o
.text: 00002 A00 ; .got:main_ptr↓o
.text: 00002 A00 argc = R0 ; int
.text: 00002 A00 argv = R1 ; unsigned __int8 **
.text: 00002 A00 ; __unwind {
.text: 00002 A00 PUSH { R7 , LR }
.text: 00002 A02 MOV R7 , SP
.text: 00002 A04 LDR argc , = ( aN1D - 0x2A0C ) ; "n1 = %d\n"
.text: 00002 A06 MOVS argv , #3
.text: 00002 A08 ADD R0 , PC ; "n1 = %d\n"
.text: 00002 A0A BLX printf
.text: 00002 A0E MOVS R0 , #0
.text: 00002 A10 POP { R7 , PC }
.text: 00002 A10 ; 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: 00002 A30 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text: 00002 A30 EXPORT main
.text: 00002 A30 main ; DATA XREF: .text:000029EC↑o
.text: 00002 A30 ; .got:main_ptr↓o
.text: 00002 A30
.text: 00002 A30 var_10 = - 0x10
.text: 00002 A30 var_C = - 0xC
.text: 00002 A30
.text: 00002 A30 argc = R0 ; int
.text: 00002 A30 argv = R1 ; unsigned __int8 **
.text: 00002 A30 ; __unwind {
.text: 00002 A30 PUSH { R4 , R5 , R7 , LR }
.text: 00002 A32 ADD R7 , SP , #8
.text: 00002 A34 SUB SP , SP , #8
.text: 00002 A36 MOV R4 , argc
.text: 00002 A38 argc = R4 ; int
.text: 00002 A38 LDR R0 , = ( __stack_chk_guard_ptr - 0x2A3E )
.text: 00002 A3A ADD R0 , PC ; __stack_chk_guard_ptr
.text: 00002 A3C LDR R5 , [ R0 ] ; __stack_chk_guard
.text: 00002 A3E LDR argv , [ R5 ]
.text: 00002 A40 LDR R0 , = ( aD - 0x2A4A ) ; "%d"
.text: 00002 A42 STR R1 , [ SP , #0x10+var_C]
.text: 00002 A44 n1 = R4 ; int
.text: 00002 A44 MOVS R1 , #0
.text: 00002 A46 ADD R0 , PC ; "%d" ; format
.text: 00002 A48 STR R1 , [ SP , #0x10+var_10]
.text: 00002 A4A MOV R1 , SP
.text: 00002 A4C BLX scanf
.text: 00002 A50 argc = R4 ; int
.text: 00002 A50 LDR R1 , [ SP , #0x10+var_10]
.text: 00002 A52 n2 = R1 ; int
.text: 00002 A52 LDR R0 , = ( aN1D - 0x2A5A ) ; "n1 = %d\n"
.text: 00002 A54 SUBS n2 , argc , n2
.text: 00002 A56 ADD R0 , PC ; "n1 = %d\n"
.text: 00002 A58 SUBS R1 , #0x5F ; '_'
.text: 00002 A5A n1 = R1 ; int
.text: 00002 A5A BLX printf
.text: 00002 A5E LDR R0 , [ SP , #0x10+var_C]
.text: 00002 A60 LDR R1 , [ R5 ]
.text: 00002 A62 SUBS R0 , R1 , R0
.text: 00002 A64 ITTT EQ
.text: 00002 A66 MOVEQ R0 , #0
.text: 00002 A68 ADDEQ SP , SP , #8
.text: 00002 A6A POPEQ { argc , R5 , R7 , PC }
.text: 00002 A6C BLX __stack_chk_fail
.text: 00002 A6C ; 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: 00002 A00 main ; DATA XREF: .text:000029BC↑o
.text: 00002 A00 ; .got:main_ptr↓o
.text: 00002 A00 argv = R1 ; unsigned __int8 **
.text: 00002 A00 argc = R0 ; int
.text: 00002 A00 ; __unwind {
.text: 00002 A00 PUSH { R7 , LR }
.text: 00002 A02 MOV R7 , SP
.text: 00002 A04 n2 = R0 ; int
.text: 00002 A04 LDR R2 , = ( aN115D - 0x2A0E ) ; "n1 * 15 = %d\n"
.text: 00002 A06 RSB.W argv , n2 , n2 , LSL #4
.text: 00002 A0A ADD R2 , PC ; "n1 * 15 = %d\n"
.text: 00002 A0C MOV n2 , R2 ; format
.text: 00002 A0E BLX printf
.text: 00002 A12 MOVS R0 , #0
.text: 00002 A14 POP { R7 , PC }
.text: 00002 A14 ; 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: 00002 A00 main ; DATA XREF: .text:000029BC↑o
.text: 00002 A00 ; .got:main_ptr↓o
.text: 00002 A00 argc = R0 ; int
.text: 00002 A00 argv = R1 ; unsigned __int8 **
.text: 00002 A00 ; __unwind {
.text: 00002 A00 PUSH { R7 , LR }
.text: 00002 A02 MOV R7 , SP
.text: 00002 A04 LDR R2 , = ( aArgc8 - 0x2A0C ) ; "argc / 8"
.text: 00002 A06 LSRS argv , argc , #3
.text: 00002 A08 ADD R2 , PC ; "argc / 8"
.text: 00002 A0A MOV argc , R2 ; format
.text: 00002 A0C BLX printf
.text: 00002 A10 MOVS R0 , #0
.text: 00002 A12 POP { R7 , PC }
.text: 00002 A12 ; 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: 00000000000006 A8 main ; DATA XREF: LOAD:0000000000000448↑o
.text: 00000000000006 A8 ; .got:main_ptr↓o
.text: 00000000000006 A8
.text: 00000000000006 A8 var_s0 = 0
.text: 00000000000006 A8
.text: 00000000000006 A8 argc = X0 ; int
.text: 00000000000006 A8 argv = X1 ; unsigned __int8 **
.text: 00000000000006 A8 ; __unwind {
.text: 00000000000006 A8 STP X29 , X30 , [ SP , #-0x10+var_s0]!
.text: 00000000000006 AC MOV X29 , SP
.text: 00000000000006 B0 LSR W1 , W0 , #3
.text: 00000000000006 B4 ADRL X0 , aArgc8 ; "argc / 8"
.text: 00000000000006 BC BL .printf
.text: 00000000000006 C0 MOV W0 , WZR
.text: 00000000000006 C4 LDP X29 , X30 , [ SP + var_s0 ], #0x10
.text: 00000000000006 C8 RET
.text: 00000000000006 C8 ; } // starts at 6A8
.text: 00000000000006 C8 ; End of function main
1
2
//右移3位
LSR W1 , W0 , # 3
总结:
除数为非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: 00002 A00 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text: 00002 A00 EXPORT main
.text: 00002 A00 main ; DATA XREF: .text:000029BC↑o
.text: 00002 A00 ; .got:main_ptr↓o
.text: 00002 A00 argc = R0 ; int
.text: 00002 A00 argv = R1 ; unsigned __int8 **
.text: 00002 A00 ; __unwind {
.text: 00002 A00 PUSH { R7 , LR }
.text: 00002 A02 MOV R7 , SP
.text: 00002 A04 MOV R1 , #0x38E38E39
.text: 00002 A0C UMULL.W argc , R1 , argc , R1
.text: 00002 A10 LDR R0 , = ( aArgc9 - 0x2A16 ) ; "argc / 9"
.text: 00002 A12 ADD R0 , PC ; "argc / 9"
.text: 00002 A14 LSRS R1 , R1 , #1
.text: 00002 A16 BLX printf
.text: 00002 A1A MOVS R0 , #0
.text: 00002 A1C POP { R7 , PC }
.text: 00002 A1C ; 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: 00000000000006 A8 main ; DATA XREF: LOAD:0000000000000448↑o
.text: 00000000000006 A8 ; .got:main_ptr↓o
.text: 00000000000006 A8
.text: 00000000000006 A8 var_s0 = 0
.text: 00000000000006 A8
.text: 00000000000006 A8 argc = X0 ; int
.text: 00000000000006 A8 argv = X1 ; unsigned __int8 **
.text: 00000000000006 A8 ; __unwind {
.text: 00000000000006 A8 STP X29 , X30 , [ SP , #-0x10+var_s0]!
.text: 00000000000006 AC MOV X29 , SP
.text: 00000000000006 B0 MOV W8 , #0x38E38E39
.text: 00000000000006 B8 UMULL X8 , W0 , W8
.text: 00000000000006 BC ADRP argc , #aArgc9@PAGE ; "argc / 9"
.text: 00000000000006 C0 LSR argv , X8 , #33 ; '!'
.text: 00000000000006 C4 ADD X0 , X0 , #aArgc9@PAGEOFF ; "argc / 9"
.text: 00000000000006 C8 BL .printf
.text: 00000000000006 CC MOV W0 , WZR
.text: 00000000000006 D0 LDP X29 , X30 , [ SP + var_s0 ], #0x10
.text: 00000000000006 D4 RET
.text: 00000000000006 D4 ; } // starts at 6A8
.text: 00000000000006 D4 ; 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: 00002 A00 main ; DATA XREF: .text:000029BC↑o
.text: 00002 A00 ; .got:main_ptr↓o
.text: 00002 A00 argc = R0 ; int
.text: 00002 A00 argv = R1 ; unsigned __int8 **
.text: 00002 A00 ; __unwind {
.text: 00002 A00 PUSH { R7 , LR }
.text: 00002 A02 MOV R7 , SP
.text: 00002 A04 MOVW argv , #0x4925
.text: 00002 A08 LDR R2 , = ( aArgc7 - 0x2A16 ) ; "argc / 7"
.text: 00002 A0A MOVT R1 , #0x2492
.text: 00002 A0E UMULL.W R1 , R3 , argc , R1
.text: 00002 A12 ADD R2 , PC ; "argc / 7"
.text: 00002 A14 SUBS argc , argc , R3
.text: 00002 A16 ADD.W R0 , R3 , R0 , LSR #1
.text: 00002 A1A LSRS R1 , R0 , #2
.text: 00002 A1C MOV R0 , R2 ; format
.text: 00002 A1E BLX printf
.text: 00002 A22 MOVS R0 , #0
.text: 00002 A24 POP { R7 , PC }
.text: 00002 A24 ; 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: 00000000000006 A8 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text: 00000000000006 A8 EXPORT main
.text: 00000000000006 A8 main ; DATA XREF: LOAD:0000000000000448↑o
.text: 00000000000006 A8 ; .got:main_ptr↓o
.text: 00000000000006 A8
.text: 00000000000006 A8 var_s0 = 0
.text: 00000000000006 A8
.text: 00000000000006 A8 argc = X0 ; int
.text: 00000000000006 A8 argv = X1 ; unsigned __int8 **
.text: 00000000000006 A8 ; __unwind {
.text: 00000000000006 A8 STP X29 , X30 , [ SP , #-0x10+var_s0]!
.text: 00000000000006 AC MOV X29 , SP
.text: 00000000000006 B0 MOV W8 , #0x24924925
.text: 00000000000006 B8 UMULL X8 , W0 , W8
.text: 00000000000006 BC LSR X8 , X8 , #32 ; ' '
.text: 00000000000006 C0 SUB W9 , W0 , W8
.text: 00000000000006 C4 ADD W8 , W8 , W9 , LSR #1
.text: 00000000000006 C8 ADRP argc , #aArgc7@PAGE ; "argc / 7"
.text: 00000000000006 CC LSR W1 , W8 , #2
.text: 00000000000006 D0 ADD X0 , X0 , #aArgc7@PAGEOFF ; "argc / 7"
.text: 00000000000006 D4 BL .printf
.text: 00000000000006 D8 MOV W0 , WZR
.text: 00000000000006 DC LDP X29 , X30 , [ SP + var_s0 ], #0x10
.text: 00000000000006 E0 RET
.text: 00000000000006 E0 ; } // starts at 6A8
.text: 00000000000006 E0 ; 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: 00002 A00 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text: 00002 A00 EXPORT main
.text: 00002 A00 main ; DATA XREF: .text:000029BC↑o
.text: 00002 A00 ; .got:main_ptr↓o
.text: 00002 A00 argc = R0 ; int
.text: 00002 A00 argv = R1 ; unsigned __int8 **
.text: 00002 A00 ; __unwind {
.text: 00002 A00 PUSH { R7 , LR }
.text: 00002 A02 MOV R7 , SP
.text: 00002 A04 LDR R2 , = ( aArgc8 - 0x2A10 ) ; "argc / 8"
.text: 00002 A06 ASRS argv , argc , #0x1F
.text: 00002 A08 ADD.W argc , argc , R1 , LSR #29
.text: 00002 A0C ADD R2 , PC ; "argc / 8"
.text: 00002 A0E ASRS R1 , R0 , #3
.text: 00002 A10 MOV R0 , R2 ; format
.text: 00002 A12 BLX printf
.text: 00002 A16 MOVS R0 , #0
.text: 00002 A18 POP { R7 , PC }
.text: 00002 A18 ; 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: 00000000000006 A8 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text: 00000000000006 A8 EXPORT main
.text: 00000000000006 A8 main ; DATA XREF: LOAD:0000000000000448↑o
.text: 00000000000006 A8 ; .got:main_ptr↓o
.text: 00000000000006 A8
.text: 00000000000006 A8 var_s0 = 0
.text: 00000000000006 A8
.text: 00000000000006 A8 argc = X0 ; int
.text: 00000000000006 A8 argv = X1 ; unsigned __int8 **
.text: 00000000000006 A8 ; __unwind {
.text: 00000000000006 A8 STP X29 , X30 , [ SP , #-0x10+var_s0]!
.text: 00000000000006 AC MOV X29 , SP
.text: 00000000000006 B0 ADD W8 , W0 , #7
.text: 00000000000006 B4 CMP W0 , #0
.text: 00000000000006 B8 CSEL W8 , W8 , W0 , LT
.text: 00000000000006 BC ADRP argc , #aArgc8@PAGE ; "argc / 8"
.text: 00000000000006 C0 ASR W1 , W8 , #3
.text: 00000000000006 C4 ADD X0 , X0 , #aArgc8@PAGEOFF ; "argc / 8"
.text: 00000000000006 C8 BL .printf
.text: 00000000000006 CC MOV W0 , WZR
.text: 00000000000006 D0 LDP X29 , X30 , [ SP + var_s0 ], #0x10
.text: 00000000000006 D4 RET
.text: 00000000000006 D4 ; } // starts at 6A8
.text: 00000000000006 D4 ; 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: 00002 A00 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text: 00002 A00 EXPORT main
.text: 00002 A00 main ; DATA XREF: .text:000029BC↑o
.text: 00002 A00 ; .got:main_ptr↓o
.text: 00002 A00 argc = R0 ; int
.text: 00002 A00 argv = R1 ; unsigned __int8 **
.text: 00002 A00 ; __unwind {
.text: 00002 A00 PUSH { R7 , LR }
.text: 00002 A02 MOV R7 , SP
.text: 00002 A04 MOV R1 , #0x38E38E39
.text: 00002 A0C SMMUL.W R1 , argc , R1
.text: 00002 A10 LDR argc , = ( aArgc9 - 0x2A16 ) ; "argc / 9"
.text: 00002 A12 ADD R0 , PC ; "argc / 9"
.text: 00002 A14 ASRS R2 , R1 , #1
.text: 00002 A16 ADD.W R1 , R2 , R1 , LSR #31
.text: 00002 A1A BLX printf
.text: 00002 A1E MOVS R0 , #0
.text: 00002 A20 POP { R7 , PC }
.text: 00002 A20 ; 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: 00000000000006 A8 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text: 00000000000006 A8 EXPORT main
.text: 00000000000006 A8 main ; DATA XREF: LOAD:0000000000000448↑o
.text: 00000000000006 A8 ; .got:main_ptr↓o
.text: 00000000000006 A8
.text: 00000000000006 A8 var_s0 = 0
.text: 00000000000006 A8
.text: 00000000000006 A8 argc = X0 ; int
.text: 00000000000006 A8 argv = X1 ; unsigned __int8 **
.text: 00000000000006 A8 ; __unwind {
.text: 00000000000006 A8 STP X29 , X30 , [ SP , #-0x10+var_s0]!
.text: 00000000000006 AC MOV X29 , SP
.text: 00000000000006 B0 MOV W8 , #0x38E38E39
.text: 00000000000006 B8 SMULL X8 , W0 , W8
.text: 00000000000006 BC LSR X9 , X8 , #0x3F ; '?'
.text: 00000000000006 C0 ASR X8 , X8 , #0x21 ; '!'
.text: 00000000000006 C4 ADRP argc , #aArgc9@PAGE ; "argc / 9"
.text: 00000000000006 C8 ADD W1 , W8 , W9
.text: 00000000000006 CC ADD X0 , X0 , #aArgc9@PAGEOFF ; "argc / 9"
.text: 00000000000006 D0 BL .printf
.text: 00000000000006 D4 MOV W0 , WZR
.text: 00000000000006 D8 LDP X29 , X30 , [ SP + var_s0 ], #0x10
.text: 00000000000006 DC RET
.text: 00000000000006 DC ; } // starts at 6A8
.text: 00000000000006 DC ; 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: 00002 A00 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text: 00002 A00 EXPORT main
.text: 00002 A00 main ; DATA XREF: .text:000029BC↑o
.text: 00002 A00 ; .got:main_ptr↓o
.text: 00002 A00 argc = R0 ; int
.text: 00002 A00 argv = R1 ; unsigned __int8 **
.text: 00002 A00 ; __unwind {
.text: 00002 A00 PUSH { R7 , LR }
.text: 00002 A02 MOV R7 , SP
.text: 00002 A04 MOV R1 , #0x92492493
.text: 00002 A0C SMMLA.W R1 , R1 , argc , argc
.text: 00002 A10 LDR argc , = ( aArgc7 - 0x2A16 ) ; "argc / 7"
.text: 00002 A12 ADD R0 , PC ; "argc / 7"
.text: 00002 A14 ASRS R2 , R1 , #2
.text: 00002 A16 ADD.W R1 , R2 , R1 , LSR #31
.text: 00002 A1A BLX printf
.text: 00002 A1E MOVS R0 , #0
.text: 00002 A20 POP { R7 , PC }
.text: 00002 A20 ; 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: 00000000000006 A8 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text: 00000000000006 A8 EXPORT main
.text: 00000000000006 A8 main ; DATA XREF: LOAD:0000000000000448↑o
.text: 00000000000006 A8 ; .got:main_ptr↓o
.text: 00000000000006 A8
.text: 00000000000006 A8 var_s0 = 0
.text: 00000000000006 A8
.text: 00000000000006 A8 argc = X0 ; int
.text: 00000000000006 A8 argv = X1 ; unsigned __int8 **
.text: 00000000000006 A8 ; __unwind {
.text: 00000000000006 A8 STP X29 , X30 , [ SP , #-0x10+var_s0]!
.text: 00000000000006 AC MOV X29 , SP
.text: 00000000000006 B0 MOV W8 , #0x92492493
.text: 00000000000006 B8 SMULL X8 , W0 , W8
.text: 00000000000006 BC LSR X8 , X8 , #0x20 ; ' '
.text: 00000000000006 C0 ADD W8 , W8 , W0
.text: 00000000000006 C4 ASR W9 , W8 , #2
.text: 00000000000006 C8 ADRP argc , #aArgc7@PAGE ; "argc / 7"
.text: 00000000000006 CC ADD W1 , W9 , W8 , LSR #31
.text: 00000000000006 D0 ADD X0 , X0 , #aArgc7@PAGEOFF ; "argc / 7"
.text: 00000000000006 D4 BL .printf
.text: 00000000000006 D8 MOV W0 , WZR
.text: 00000000000006 DC LDP X29 , X30 , [ SP + var_s0 ], #0x10
.text: 00000000000006 E0 RET
.text: 00000000000006 E0 ; } // starts at 6A8
.text: 00000000000006 E0 ; 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: 00002 A00 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text: 00002 A00 EXPORT main
.text: 00002 A00 main ; DATA XREF: .text:000029BC↑o
.text: 00002 A00 ; .got:main_ptr↓o
.text: 00002 A00 argc = R0 ; int
.text: 00002 A00 argv = R1 ; unsigned __int8 **
.text: 00002 A00 ; __unwind {
.text: 00002 A00 PUSH { R7 , LR }
.text: 00002 A02 MOV R7 , SP
.text: 00002 A04 LDR R2 , = ( aArgc8 - 0x2A12 ) ; "argc / -8"
.text: 00002 A06 ASRS argv , argc , #0x1F
.text: 00002 A08 ADD.W argc , argc , R1 , LSR #29
.text: 00002 A0C MOVS R1 , #0
.text: 00002 A0E ADD R2 , PC ; "argc / -8"
.text: 00002 A10 SUB.W R1 , R1 , R0 , ASR #3
.text: 00002 A14 MOV R0 , R2 ; format
.text: 00002 A16 BLX printf
.text: 00002 A1A MOVS R0 , #0
.text: 00002 A1C POP { R7 , PC }
.text: 00002 A1C ; 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: 00000000000006 A8 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text: 00000000000006 A8 EXPORT main
.text: 00000000000006 A8 main ; DATA XREF: LOAD:0000000000000448↑o
.text: 00000000000006 A8 ; .got:main_ptr↓o
.text: 00000000000006 A8
.text: 00000000000006 A8 var_s0 = 0
.text: 00000000000006 A8
.text: 00000000000006 A8 argc = X0 ; int
.text: 00000000000006 A8 argv = X1 ; unsigned __int8 **
.text: 00000000000006 A8 ; __unwind {
.text: 00000000000006 A8 STP X29 , X30 , [ SP , #-0x10+var_s0]!
.text: 00000000000006 AC MOV X29 , SP
.text: 00000000000006 B0 ADD W8 , W0 , #7
.text: 00000000000006 B4 CMP W0 , #0
.text: 00000000000006 B8 CSEL W8 , W8 , W0 , LT
.text: 00000000000006 BC ADRP argc , #aArgc8@PAGE ; "argc / -8"
.text: 00000000000006 C0 NEG W1 , W8 , ASR #3
.text: 00000000000006 C4 ADD X0 , X0 , #aArgc8@PAGEOFF ; "argc / -8"
.text: 00000000000006 C8 BL .printf
.text: 00000000000006 CC MOV W0 , WZR
.text: 00000000000006 D0 LDP X29 , X30 , [ SP + var_s0 ], #0x10
.text: 00000000000006 D4 RET
.text: 00000000000006 D4 ; } // starts at 6A8
.text: 00000000000006 D4 ; 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: 00002 A00 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text: 00002 A00 EXPORT main
.text: 00002 A00 main ; DATA XREF: .text:000029BC↑o
.text: 00002 A00 ; .got:main_ptr↓o
.text: 00002 A00 argc = R0 ; int
.text: 00002 A00 argv = R1 ; unsigned __int8 **
.text: 00002 A00 ; __unwind {
.text: 00002 A00 PUSH { R7 , LR }
.text: 00002 A02 MOV R7 , SP
.text: 00002 A04 MOVW argv , #0xDB6D
.text: 00002 A08 LDR R2 , = ( aArgc7 - 0x2A16 ) ; "argc / -7"
.text: 00002 A0A MOVT R1 , #0x6DB6
.text: 00002 A0E SMMUL.W R1 , argc , R1
.text: 00002 A12 ADD R2 , PC ; "argc / -7"
.text: 00002 A14 SUBS argc , R1 , argc
.text: 00002 A16 ASRS R1 , R0 , #2
.text: 00002 A18 ADD.W R1 , R1 , R0 , LSR #31
.text: 00002 A1C MOV R0 , R2 ; format
.text: 00002 A1E BLX printf
.text: 00002 A22 MOVS R0 , #0
.text: 00002 A24 POP { R7 , PC }
.text: 00002 A24 ; 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: 00000000000006 A8 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text: 00000000000006 A8 EXPORT main
.text: 00000000000006 A8 main ; DATA XREF: LOAD:0000000000000448↑o
.text: 00000000000006 A8 ; .got:main_ptr↓o
.text: 00000000000006 A8
.text: 00000000000006 A8 var_s0 = 0
.text: 00000000000006 A8
.text: 00000000000006 A8 argc = X0 ; int
.text: 00000000000006 A8 argv = X1 ; unsigned __int8 **
.text: 00000000000006 A8 ; __unwind {
.text: 00000000000006 A8 STP X29 , X30 , [ SP , #-0x10+var_s0]!
.text: 00000000000006 AC MOV X29 , SP
.text: 00000000000006 B0 MOV W8 , #0x6DB6DB6D
.text: 00000000000006 B8 SMULL X8 , W0 , W8
.text: 00000000000006 BC LSR X8 , X8 , #0x20 ; ' '
.text: 00000000000006 C0 SUB W8 , W8 , W0
.text: 00000000000006 C4 ASR W9 , W8 , #2
.text: 00000000000006 C8 ADRP argc , #aArgc7@PAGE ; "argc / -7"
.text: 00000000000006 CC ADD W1 , W9 , W8 , LSR #31
.text: 00000000000006 D0 ADD X0 , X0 , #aArgc7@PAGEOFF ; "argc / -7"
.text: 00000000000006 D4 BL .printf
.text: 00000000000006 D8 MOV W0 , WZR
.text: 00000000000006 DC LDP X29 , X30 , [ SP + var_s0 ], #0x10
.text: 00000000000006 E0 RET
.text: 00000000000006 E0 ; } // starts at 6A8
.text: 00000000000006 E0 ; 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: 00002 A00 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text: 00002 A00 EXPORT main
.text: 00002 A00 main ; DATA XREF: .text:000029BC↑o
.text: 00002 A00 ; .got:main_ptr↓o
.text: 00002 A00 argc = R0 ; int
.text: 00002 A00 argv = R1 ; unsigned __int8 **
.text: 00002 A00 ; __unwind {
.text: 00002 A00 PUSH { R7 , LR }
.text: 00002 A02 MOV R7 , SP
.text: 00002 A04 MOV R1 , #0xC71C71C7
.text: 00002 A0C SMMUL.W R1 , argc , R1
.text: 00002 A10 LDR argc , = ( aArgc9 - 0x2A16 ) ; "argc / -9"
.text: 00002 A12 ADD R0 , PC ; "argc / -9"
.text: 00002 A14 ASRS R2 , R1 , #1
.text: 00002 A16 ADD.W R1 , R2 , R1 , LSR #31 ; n1
.text: 00002 A1A BLX printf
.text: 00002 A1E MOVS R0 , #0
.text: 00002 A20 POP { R7 , PC }
.text: 00002 A20 ; 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: 00000000000006 A8 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text: 00000000000006 A8 EXPORT main
.text: 00000000000006 A8 main ; DATA XREF: LOAD:0000000000000448↑o
.text: 00000000000006 A8 ; .got:main_ptr↓o
.text: 00000000000006 A8
.text: 00000000000006 A8 var_s0 = 0
.text: 00000000000006 A8
.text: 00000000000006 A8 argc = X0 ; int
.text: 00000000000006 A8 argv = X1 ; unsigned __int8 **
.text: 00000000000006 A8 ; __unwind {
.text: 00000000000006 A8 STP X29 , X30 , [ SP , #-0x10+var_s0]!
.text: 00000000000006 AC MOV X29 , SP
.text: 00000000000006 B0 MOV W8 , #0xC71C71C7
.text: 00000000000006 B8 SMULL X8 , W0 , W8
.text: 00000000000006 BC LSR X9 , X8 , #63 ; '?'
.text: 00000000000006 C0 ASR X8 , X8 , #33 ; '!'
.text: 00000000000006 C4 ADRP argc , #aArgc9@PAGE ; "argc / -9"
.text: 00000000000006 C8 ADD W1 , W8 , W9 ; n1
.text: 00000000000006 CC ADD X0 , X0 , #aArgc9@PAGEOFF ; "argc / -9"
.text: 00000000000006 D0 BL .printf
.text: 00000000000006 D4 MOV W0 , WZR
.text: 00000000000006 D8 LDP X29 , X30 , [ SP + var_s0 ], #0x10
.text: 00000000000006 DC RET
.text: 00000000000006 DC ; } // starts at 6A8
.text: 00000000000006 DC ; 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: 00002 A00 main ; DATA XREF: .text:000029BC↑o
.text: 00002 A00 ; .got:main_ptr↓o
.text: 00002 A00 argc = R0 ; int
.text: 00002 A00 argv = R1 ; unsigned __int8 **
.text: 00002 A00 ; __unwind {
.text: 00002 A00 PUSH { R7 , LR }
.text: 00002 A02 MOV R7 , SP
.text: 00002 A04 LDR R2 , = ( aArgc8 - 0x2A0E ) ; "argc % 8"
.text: 00002 A06 AND.W argv , argc , #7
.text: 00002 A0A ADD R2 , PC ; "argc % 8"
.text: 00002 A0C MOV argc , R2 ; format
.text: 00002 A0E BLX printf
.text: 00002 A12 MOVS R0 , #0
.text: 00002 A14 POP { R7 , PC }
.text: 00002 A14 ; End of function main
1
2
//R1 = argc & 7
AND.W R1 , argc , # 7
总结:
除数为非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: 00002 A00 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text: 00002 A00 EXPORT main
.text: 00002 A00 main ; DATA XREF: .text:000029BC↑o
.text: 00002 A00 ; .got:main_ptr↓o
.text: 00002 A00 argc = R0 ; int
.text: 00002 A00 argv = R1 ; unsigned __int8 **
.text: 00002 A00 ; __unwind {
.text: 00002 A00 PUSH { R7 , LR }
.text: 00002 A02 MOV R7 , SP
.text: 00002 A04 MOVW argv , #0x8E39
.text: 00002 A08 LDR R2 , = ( aArgc9 - 0x2A16 ) ; "argc % 9"
.text: 00002 A0A MOVT R1 , #0x38E3
.text: 00002 A0E UMULL.W R1 , R3 , argc , R1
.text: 00002 A12 ADD R2 , PC ; "argc % 9"
.text: 00002 A14 LSRS R1 , R3 , #1
.text: 00002 A16 ADD.W R1 , R1 , R1 , LSL #3
.text: 00002 A1A SUBS R1 , argc , R1
.text: 00002 A1C MOV argc , R2 ; format
.text: 00002 A1E BLX printf
.text: 00002 A22 MOVS R0 , #0
.text: 00002 A24 POP { R7 , PC }
.text: 00002 A24 ; 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: 00002 A00 main ; DATA XREF: .text:000029BC↑o
.text: 00002 A00 ; .got:main_ptr↓o
.text: 00002 A00 argc = R0 ; int
.text: 00002 A00 argv = R1 ; unsigned __int8 **
.text: 00002 A00 ; __unwind {
.text: 00002 A00 PUSH { R7 , LR }
.text: 00002 A02 MOV R7 , SP
.text: 00002 A04 LDR R2 , = ( aArgc8 - 0x2A14 ) ; "argc % 8"
.text: 00002 A06 ASRS argv , argc , #0x1F
.text: 00002 A08 ADD.W R1 , argc , R1 , LSR #29
.text: 00002 A0C BIC.W R1 , R1 , #7
.text: 00002 A10 ADD R2 , PC ; "argc % 8"
.text: 00002 A12 SUBS R1 , argc , R1
.text: 00002 A14 MOV argc , R2 ; format
.text: 00002 A16 BLX printf
.text: 00002 A1A MOVS R0 , #0
.text: 00002 A1C POP { R7 , PC }
.text: 00002 A1C ; 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: 00002 A00 main ; DATA XREF: .text:000029BC↑o
.text: 00002 A00 ; .got:main_ptr↓o
.text: 00002 A00 argc = R0 ; int
.text: 00002 A00 argv = R1 ; unsigned __int8 **
.text: 00002 A00 ; __unwind {
.text: 00002 A00 PUSH { R7 , LR }
.text: 00002 A02 MOV R7 , SP
.text: 00002 A04 MOVW argv , #0x8E39
.text: 00002 A08 LDR R2 , = ( aArgc9 - 0x2A16 ) ; "argc % 9"
.text: 00002 A0A MOVT R1 , #0x38E3
.text: 00002 A0E SMMUL.W R1 , argc , R1
.text: 00002 A12 ADD R2 , PC ; "argc % 9"
.text: 00002 A14 ASRS R3 , R1 , #1
.text: 00002 A16 ADD.W R1 , R3 , R1 , LSR #31
.text: 00002 A1A ADD.W R1 , R1 , R1 , LSL #3
.text: 00002 A1E SUBS R1 , argc , R1
.text: 00002 A20 MOV argc , R2 ; format
.text: 00002 A22 BLX printf
.text: 00002 A26 MOVS R0 , #0
.text: 00002 A28 POP { R7 , PC }
.text: 00002 A28 ; 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:
while
源代码:
1
2
3
4
while ( argc < 10 ) {
printf ( "%d \n " , argc );
argc ++ ;
}
arm-v7a:
do-while
源代码:
1
2
3
4
do {
printf ( "%d \n " , argc );
argc ++ ;
} while ( argc < 10 );
arm-v7a:
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:
函数
这一部分跟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:
从上面可以看到,前4个整型参数放在寄存器R0-R3中,后面的参数就入栈了,整型返回值放在R0中.
arm-v8a:
从上面可以看到,前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:
从上面可以看到,浮点传参跟整型传参没有区别,前4个参数放R0-R3,后面的参数入栈,浮点返回值放在R0中.
arm-v8a:
从上面可以看到,前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:
从上面可以看到,混合传参对32位没有影响,前4个参数放R0-R3中,后面的参数入栈,长整型的返回值放在R1 .
arm-v8a:
从上面可以看到,对于混合传参,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 ;
}
总结:
全局变量初始化以及初始化函数在.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 ;
}
总结:
这部分跟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
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 ;
}
总结:
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 ;
}
总结:
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
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
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
父类构造在填虚表之前,
成员对象构造在填虚表之后.