asm {
PUT_DEC_U64::
//RAX is number to print in decimal.
//Preserves all registers.
                PUSH        RBP
                MOV         RBP,RSP
                SUB         RSP, 24                 //24 char buffer on stack

//Save registers which C code is free to clobber.  We don't have to for C callers,
//but this function will be nice for ASM callers if it saves all registers.
                PUSH_C_REGS

                PUSH        RSI                 //See REGG_LOCAL_VARS&REGG_LOCAL_NON_PTR_VARS
                LEA         RSI, -1[RBP]        //Load address of end of buffer.
                                                                //We picked RSI because of PUT_STR
                                                                //We'll move backward
                MOV         U8 [RSI], 0         //Terminator

                TEST        RAX, RAX            //Special case -- zero
                JNZ         @@05
                DEC         RSI
                MOV         U8 [RSI], '0'
                JMP         @@15

@@05:           MOV         RBX, 10             //Divides by 10

@@10:           XOR         RDX, RDX
                DIV         RBX                 //RAX=(RDX:RAX)/RBX with remainder in RDX
                ADD         RDX, '0'
                DEC         RSI
                MOV         U8 [RSI], DL
                TEST        RAX,RAX
                JNZ         @@10

@@15:           CALL        PUT_STR
                POP         RSI
                POP_C_REGS
                LEAVE
                RET

_DO_IT::        //The convention is C-callable routines have underscores.
                MOV         RAX, 122333221
                CALL        PUT_DEC_U64
                MOV         RAX, '\n'
                CALL        PUT_CHARS
                RET
}

Call(_DO_IT);