# ARM Thumb, no div instructions, 43 bytes `f7ff fffe` represents placeholders for libc calls, to `scanf` and `printf` respectively. ```lang-none b503 4669 a008 f7ff fffe bc03 2802 d907 2202 0001 1a89 d003 d8fc 3201 4282 d1f8 a001 f7ff fffe bd00 6425 00 ``` Assembly code: ```lang-armasm .globl main .thumb .thumb_func main: push {r0, r1, lr} mov r1, sp adr r0, printf_scanf_str bl scanf pop {r0, r1} cmp r0, #2 bls .Ltrue movs r2, #2 .Lloop1: movs r1, r0 .Ldivloop: subs r1, r2 beq .Lfalse bhi .Ldivloop .Ldivloop_end: adds r2, #1 cmp r2, r0 bne .Lloop1 .Ltrue: @ movs r1, #1 @ optional, needs odd load address but will print 1 instead of a random nonzero value .Lfalse: adr r0, printf_scanf_str bl printf pop {pc} printf_scanf_str: .asciz "%d" ``` Accepts a number from stdin, and prints nonzero if it is a prime, or zero if it isn't. ### Walkthrough Behold, the world's least efficient prime searcher. It is a brute force modulo check using a subtraction loop with zero shortcuts. <hr/> Here, we use a trick with `push` to make space for the `scanf` output *and* save the link register. `push` will subtract from `sp` and store the registers in ascending order in memory. So for example, `push {r0, r1, lr}` will end up like this: ```lang-none | sp + 0 | sp + 4 | sp + 8 | | argc | argv | return | ``` We don't actually care about `argc` - we care about the space on `sp`. We can then just pass the stack pointer directly to `scanf`. We do sorta care about `argv`. Not about what it points to, but that it is a valid (non-zero) pointer. `scanf("%d", &r0)` ```lang-armasm main: push {r0, r1, lr} mov r1, sp adr r0, printf_str bl scanf ``` Then, we can `pop` the result from `scanf` we stored into `r0`, and `argv` into `r1` as the "non-zero" value for our short circuit loop. ```lang-armasm pop {r0, r1} ``` Immediately return true for values <= 2. ```lang-armasm cmp r0, #2 bls .Ltrue ``` Begin factorizing against 2. ```lang-armasm movs r2, #2 ``` Use a subtraction loop on a copy of `r0` to check if `r0 % r2 == 0`. Specifically, the `subs` will reach zero on an even multiple and set the zero flag (which corresponds to the `eq` condition). Otherwise, we loop until it underflows (not `hi`) ```lang-armasm .Lloop1: movs r1, r0 .Ldivloop: subs r1, r2 beq .Lfalse bhi .Ldivloop ``` Increment the number we factor against and loop if it is not equal to `r0`. ```lang-armasm .Ldivloop_end: adds r2, #1 cmp r2, r0 bne .Lloop1 ``` Optionally, with the `true` condition, we set `r1` to `1` if it is a prime. But non-zero is "truthy" enough for us even if it is a little ugly. It will either be the last inverted modulo we tested, or the address of `argv`, all of which will be non-zero. Due to how our subtraction loop works, by the time we jump to `.Lfalse`, `r1` will already be zero. ```lang-armasm .Ltrue: @ movs r1, #1 @ optional, needs odd load address but will print 1 instead of a random nonzero value .Lfalse: ``` `r1` is already conveniently (and intentionally) in the right place to forward directly to `printf`, and all we need to do is reload the printf/scanf string to `r0` (no easy way around this) and call `printf`. Note that due to how `pop` works in Thumb, it isn't really that useful to do tail calls. ```lang-armasm adr r0, printf_scanf_str bl printf ``` Last, pop the return address from `lr` we `push`ed earlier directly into the program counter to return from `main`. ```lang-armasm pop {pc} ```