// uuid256.x86_64.S — UUID256 (README.md, random layout) in x86-64 assembly (AT&T syntax).  No libc code beyond 3 calls on macOS.
//
//   macOS (also runs on Apple silicon under Rosetta 2):
//       cc -arch x86_64 -o /tmp/uuid256-x64 uuid256.x86_64.S && /tmp/uuid256-x64 5
//   Linux (raw syscalls, no libc; cross-built and run under the Unicorn harness here):
//       zig cc -target x86_64-linux-musl -nostdlib -static uuid256.x86_64.S -o /tmp/uuid256-x64-linux
//       python3 emulate.py /tmp/uuid256-x64-linux 5           (or just run it on any x86-64 Linux box)
//   Usage:  prog [N]     print N ids (default 10; 0 prints nothing; non-numeric → exit 2), one canonical 16-8-8-8-24 line each
//           prog -       test mode: read 32 raw bytes from stdin, apply §4, print canonical
//
// What it implements:
//   §5.1  32 bytes from the OS CSPRNG (macOS getentropy(2) / Linux getrandom(2))
//   §4    byte 12 = (byte 12 & 0x0F) | 0x40 (version 4);  byte 16 = (byte 16 & 0x3F) | 0x80 (variant 10)
//   §3.1  64 lowercase hex digits with hyphens after digits 16, 24, 32, 40
//
// Register use:  r12 = ids remaining · r13 = mode (0 random, 1 stdin) · r14 = &hexdigits
//                0(%rsp)..31 = the 32-byte id · 32(%rsp)..100 = the 68-char text + '\n'

#ifdef __APPLE__
        .text
        .globl  _main
_main:                                          // int main(int argc, char **argv): rdi = argc, rsi = argv
#else
        .text
        .globl  _start
_start:                                         // Linux process entry: [rsp] = argc, 8(%rsp) = argv[0] ...
        movq    (%rsp), %rdi
        leaq    8(%rsp), %rsi
#endif
        pushq   %rbp
        pushq   %rbx
        pushq   %r12
        pushq   %r13
        pushq   %r14
        pushq   %r15
        subq    $136, %rsp                      // id (32 B) + text (69 B); keeps rsp 16-aligned for calls on macOS
        movq    $10, %r12                       // N default
        xorq    %r13, %r13                      // mode: random
        leaq    hexdigits(%rip), %r14
        cmpq    $2, %rdi                        // argc < 2 → defaults
        jl      Lloop
        movq    8(%rsi), %rbx                   // argv[1]
        cmpb    $45, (%rbx)                     // '-' → test mode
        jne     Latoi
        cmpb    $0, 1(%rbx)
        jne     Latoi
        movq    $1, %r13
        movq    $1, %r12
        jmp     Lloop
Latoi:                                          // N = decimal(argv[1]); 0 → print nothing; non-numeric → exit 2
        xorq    %r12, %r12
Latoi_next:
        movzbl  (%rbx), %eax
        testl   %eax, %eax
        jz      Latoi_done
        subl    $48, %eax                       // '0'
        cmpl    $9, %eax
        ja      Latoi_bad
        imulq   $10, %r12, %r12
        addq    %rax, %r12
        incq    %rbx
        jmp     Latoi_next
Latoi_bad:
        movl    $2, %eax                        // non-numeric argument → usage error, exit 2
        jmp     Lexit
Latoi_done:                                     // (N = 0 prints nothing and exits 0)

Lloop:
        testq   %r12, %r12
        jz      Ldone

        // ---- 32 bytes: §5.1 OS CSPRNG, or stdin in test mode -------------------------
        testq   %r13, %r13
        jnz     Lstdin
#ifdef __APPLE__
        movq    %rsp, %rdi                      // buf
        movq    $32, %rsi                       // len (getentropy allows ≤ 256)
        call    _getentropy
        testl   %eax, %eax
        jnz     Lfail
#else
        movq    $318, %rax                      // SYS_getrandom
        movq    %rsp, %rdi
        movq    $32, %rsi
        xorq    %rdx, %rdx                      // flags
        syscall
        cmpq    $32, %rax
        jne     Lfail
#endif
        jmp     Lhave
Lstdin:
        xorq    %r15, %r15                      // bytes read so far; loop until all 32 arrive (a pipe may deliver them in pieces)
Lread_more:
#ifdef __APPLE__
        xorl    %edi, %edi                      // fd 0
        leaq    (%rsp,%r15), %rsi               // buf + got
        movq    $32, %rdx
        subq    %r15, %rdx                      // remaining
        call    _read
#else
        xorq    %rax, %rax                      // SYS_read
        xorq    %rdi, %rdi
        leaq    (%rsp,%r15), %rsi
        movq    $32, %rdx
        subq    %r15, %rdx
        syscall
#endif
        testq   %rax, %rax
        jle     Lfail                           // EOF or error before 32 bytes
        addq    %rax, %r15
        cmpq    $32, %r15
        jl      Lread_more
Lhave:
        // ---- §4: version nibble (byte 12) and variant bits (byte 16) ------------------
        andb    $0x0F, 12(%rsp)
        orb     $0x40, 12(%rsp)                 // ver = 4  → hex digit 24 is '4'
        andb    $0x3F, 16(%rsp)
        orb     $0x80, 16(%rsp)                 // var = 10 → hex digit 32 in 8..b

        // ---- §3.1: canonical text 16-8-8-8-24 -----------------------------------------
        leaq    32(%rsp), %rdi                  // output cursor
        xorq    %rcx, %rcx                      // byte index i
Lfmt:
        movzbl  (%rsp,%rcx), %eax
        movl    %eax, %edx
        shrl    $4, %eax
        movb    (%r14,%rax), %al                // high nibble → hex char
        movb    %al, (%rdi)
        andl    $0x0F, %edx
        movb    (%r14,%rdx), %dl                // low nibble  → hex char
        movb    %dl, 1(%rdi)
        addq    $2, %rdi
        incq    %rcx
        cmpq    $32, %rcx
        je      Lfmt_done
        cmpq    $8, %rcx                        // hyphen after bytes 8, 12, 16, 20
        je      Lhyphen                         //   (= hex digits 16, 24, 32, 40)
        cmpq    $12, %rcx
        je      Lhyphen
        cmpq    $16, %rcx
        je      Lhyphen
        cmpq    $20, %rcx
        jne     Lfmt
Lhyphen:
        movb    $45, (%rdi)                     // '-'
        incq    %rdi
        jmp     Lfmt
Lfmt_done:
        movb    $10, (%rdi)                     // '\n'
#ifdef __APPLE__
        movl    $1, %edi                        // fd 1
        leaq    32(%rsp), %rsi
        movq    $69, %rdx                       // 68 chars + newline
        call    _write
#else
        movq    $1, %rax                        // SYS_write
        movq    $1, %rdi
        leaq    32(%rsp), %rsi
        movq    $69, %rdx
        syscall
#endif
        decq    %r12
        jmp     Lloop

Lfail:
        movl    $1, %eax
        jmp     Lexit
Ldone:
        xorl    %eax, %eax
Lexit:
#ifdef __APPLE__
        addq    $136, %rsp
        popq    %r15
        popq    %r14
        popq    %r13
        popq    %r12
        popq    %rbx
        popq    %rbp
        ret
#else
        movl    %eax, %edi                      // exit status
        movq    $60, %rax                       // SYS_exit
        syscall
#endif

hexdigits:
        .ascii  "0123456789abcdef"
