When I was debugging an app on iPhone 4 (armv7), I found a function call:
1 |
0x22ad42 <+238>: blx 0x40e6dc ; symbol stub for: __moddi3 |
Since ARM does not have Division/Modulo operators, compilers use other ways making your code work on devices like iPhone.
I followed the __moddi3 on iPhone 4, the moddi3() is provided by llvm’s compiler-rt (lib/builtins/moddi3.c).
Parameters a and b are 64-bit long and returned value is also 64-bit.
But in ARMv7, registers are 32-bit long. I’m trying to find out which registers are used.
I wrote a simple C file and compile to armv7 and x86_64
1 2 3 4 5 6 7 8 9 10 11 12 |
#include <stdio.h> int main() { long long a = 365; long long b = 14; long long c = a % b; long long d = a / b; printf("%llu %% %llu = %llu\n%llu / %llu = %llu\n", a, b, c, a, b, d); return 0; } |
Compile to x86_64
1 |
clang -g -o mod_x86_64 mod.c |
Disassembe x86_64
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 |
$ otool -tV mod_x86_64 mod_x86_64: (__TEXT,__text) section _main: 0000000100000ed0 pushq %rbp 0000000100000ed1 movq %rsp, %rbp 0000000100000ed4 subq $0x40, %rsp 0000000100000ed8 leaq 0x8b(%rip), %rdi ## literal pool for: "%llu %% %llu = %llu\n%llu / %llu = %llu\n" 0000000100000edf movl $0x0, -0x4(%rbp) 0000000100000ee6 movq $0x16d, -0x10(%rbp) ## imm = 0x16D 0000000100000eee movq $0xe, -0x18(%rbp) 0000000100000ef6 movq -0x10(%rbp), %rax 0000000100000efa cqto 0000000100000efc idivq -0x18(%rbp) 0000000100000f00 movq %rdx, -0x20(%rbp) 0000000100000f04 movq -0x10(%rbp), %rdx 0000000100000f08 movq %rdx, %rax 0000000100000f0b cqto 0000000100000f0d idivq -0x18(%rbp) 0000000100000f11 movq %rax, -0x28(%rbp) 0000000100000f15 movq -0x10(%rbp), %rsi 0000000100000f19 movq -0x18(%rbp), %rax 0000000100000f1d movq -0x20(%rbp), %rcx 0000000100000f21 movq -0x10(%rbp), %r8 0000000100000f25 movq -0x18(%rbp), %r9 0000000100000f29 movq -0x28(%rbp), %r10 0000000100000f2d movq %rax, %rdx 0000000100000f30 movq %r10, (%rsp) 0000000100000f34 movb $0x0, %al 0000000100000f36 callq 0x100000f4a ## symbol stub for: _printf 0000000100000f3b xorl %r11d, %r11d 0000000100000f3e movl %eax, -0x2c(%rbp) 0000000100000f41 movl %r11d, %eax 0000000100000f44 addq $0x40, %rsp 0000000100000f48 popq %rbp 0000000100000f49 retq |
x86_64 uses idivq, in this program:
1 2 3 4 |
dividend: $rax divisor: $rbp-0x18 quotient: $rax remainder: $rdx |
Compile to armv7
1 2 3 |
# CC="$(xcrun --sdk iphoneos -f clang)" # SDKROOT=$(xcrun --sdk iphoneos --show-sdk-path) # $CC -isysroot $SDKROOT -arch armv7 -g -o mod_armv7 mod.c |
Disassemble armv7
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 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
$ otool -tV mod_armv7 mod_armv7: (__TEXT,__text) section _main: 0000bec8 b5f0 push {r4, r5, r6, r7, lr} 0000beca af03 add r7, sp, #0xc 0000becc e92d0d00 push.w {r8, r10, r11} 0000bed0 b096 sub sp, #0x58 0000bed2 466c mov r4, sp 0000bed4 f36f0402 bfc r4, #0, #3 0000bed8 46a5 mov sp, r4 0000beda f24000e6 movw r0, #0xe6 0000bede f2c00000 movt r0, #0x0 0000bee2 4478 add r0, pc 0000bee4 2100 movs r1, #0x0 0000bee6 9115 str r1, [sp, #0x54] 0000bee8 9113 str r1, [sp, #0x4c] 0000beea f240126d movw r2, #0x16d 0000beee 9212 str r2, [sp, #0x48] 0000bef0 9111 str r1, [sp, #0x44] 0000bef2 220e movs r2, #0xe 0000bef4 9210 str r2, [sp, #0x40] 0000bef6 9b12 ldr r3, [sp, #0x48] 0000bef8 f8dd904c ldr.w r9, [sp, #0x4c] 0000befc 900b str r0, [sp, #0x2c] 0000befe 4618 mov r0, r3 0000bf00 910a str r1, [sp, #0x28] 0000bf02 4649 mov r1, r9 0000bf04 9b0a ldr r3, [sp, #0x28] 0000bf06 f000e878 blx 0xbff8 @ symbol stub for: ___moddi3 0000bf0a 910f str r1, [sp, #0x3c] 0000bf0c 900e str r0, [sp, #0x38] 0000bf0e 9812 ldr r0, [sp, #0x48] 0000bf10 9913 ldr r1, [sp, #0x4c] 0000bf12 9a10 ldr r2, [sp, #0x40] 0000bf14 9b11 ldr r3, [sp, #0x44] 0000bf16 f000e86e blx 0xbff4 @ symbol stub for: ___divdi3 0000bf1a 910d str r1, [sp, #0x34] 0000bf1c 900c str r0, [sp, #0x30] 0000bf1e 9a12 ldr r2, [sp, #0x48] 0000bf20 9b13 ldr r3, [sp, #0x4c] 0000bf22 f8dd9040 ldr.w r9, [sp, #0x40] 0000bf26 f8ddc044 ldr.w r12, [sp, #0x44] 0000bf2a f8dde038 ldr.w lr, [sp, #0x38] 0000bf2e 9c0f ldr r4, [sp, #0x3c] 0000bf30 461d mov r5, r3 0000bf32 4616 mov r6, r2 0000bf34 46e0 mov r8, r12 0000bf36 46ca mov r10, r9 0000bf38 46eb mov r11, sp 0000bf3a f8cb1020 str.w r1, [r11, #0x20] 0000bf3e f8cb001c str.w r0, [r11, #0x1c] 0000bf42 f8cb8018 str.w r8, [r11, #0x18] 0000bf46 f8cba014 str.w r10, [r11, #0x14] 0000bf4a f8cb5010 str.w r5, [r11, #0x10] 0000bf4e f8cb600c str.w r6, [r11, #0xc] 0000bf52 f8cb4008 str.w r4, [r11, #0x8] 0000bf56 f8cbe004 str.w lr, [r11, #0x4] 0000bf5a f8cbc000 str.w r12, [r11] 0000bf5e f2400062 movw r0, #0x62 0000bf62 f2c00000 movt r0, #0x0 0000bf66 4478 add r0, pc 0000bf68 4611 mov r1, r2 0000bf6a 461a mov r2, r3 0000bf6c 464b mov r3, r9 0000bf6e f000e846 blx 0xbffc @ symbol stub for: _printf 0000bf72 2100 movs r1, #0x0 0000bf74 9009 str r0, [sp, #0x24] 0000bf76 4608 mov r0, r1 0000bf78 f1a70418 sub.w r4, r7, #0x18 0000bf7c 46a5 mov sp, r4 0000bf7e e8bd0d00 pop.w {r8, r10, r11} 0000bf82 bdf0 pop {r4, r5, r6, r7, pc} |
In armv7:
1 2 3 4 |
dividend: $r0 | ($r1 << 32) divisor: $r2 | ($r3 << 32) quotient: N/A remainder: $r0 | ($r1 << 32) |
If both dividend and divisor are less than 0x100000000.
$r2 may be negative, like 0xfffffff3. ($r3 == 0).
1 2 |
(lldb) p $r0 - $r2 (int) $0 = 14 |
means $r0 – $r2 == divisor
If signed integer $r2 is smaller than 0x80000000,
((long long) $r1 << 32 | $r0) - ((long long ) $r3 << 32 | $r2) == divisor.