# x86-64 machine code, 12 bytes


This is a function, callable with args `n=RCX`, `k=ESI`.  32-bit return value in `EAX`.

Callable from C with the x86-64 System V calling convention with dummy args to get the real args into the right registers. `uint32_t factk(int, uint32_t k, int, uint64_t n);`  I couldn't just use Windows x64 because 1-operand `mul` clobbers RDX, and we don't want REX prefixes to access R8/R9.  `n` must not have any garbage in the high 32 bits so JRCXZ works, but other than that it's all 32-bit.

NASM listing (relative address, machine code, source)

     1                         factk:
     2 00000000 6A01             push 1
     3 00000002 58               pop rax             ; retval = 1
     4 00000003 E306             jrcxz  .n_zero      ; if (n==0) return
     5                         .loop:                ; do {
     6 00000005 F7E1              mul   ecx            ; retval *= n  (clobbering RDX)
     7 00000007 29F1              sub   ecx, esi       ; n -= k
     8 00000009 77FA              ja   .loop         ; }while(sub didn't wrap or give zero)
     9                         .n_zero:
    10 0000000B C3               ret

0xc = 12 bytes


---

Test caller that passes `argc` as `k`, with `n` hard-coded.

```
align 16
global _start
_start:
  mov  esi, [rsp]
;main:
  mov  ecx, 9
  call factk

  mov  esi, eax
  mov  edx, eax
  lea  rdi, [rel print_format]
  xor  eax, eax
extern printf
  call printf
extern exit
  call exit

section .rodata
print_format: db `%#x\t%u\n`

```