Author Topic: [FASM x86] Small software stack virtual machine  (Read 772 times)

0 Members and 1 Guest are viewing this topic.

Offline 0xDADA11c7

  • NULL
  • Posts: 4
  • Cookies: 4
    • View Profile
[FASM x86] Small software stack virtual machine
« on: December 13, 2014, 08:44:54 pm »
This VM developed for cryptographic purposes. I must note, when I tell about VM, then I mean a family of similar virtual machines. The following VM is officially approved iridium sample in vacuum for use in the examples. VM size varies in ranges about 700 bytes.
Architecture:
  • Two 32-bits stack - data and return
  • VM size varies in ranges about 700 bytes.
  • Every VM is unique because unique opcodes, unique fiels and unique functions number
  • Access to memory can be in Bytes, Words (2 Bytes) and DWords (Double Words, 4 bytes)[/*]
Originally posted in Ukrainian forum
 
picovm.inc

Code: [Select]
    struct PICOVM_CONTEXT
    _dstack_size db ?
    _instruction_pointer dd ?
    _dstack_begin dd ?
    _rstack_size db ?
    _rstack_begin dd ?
    _rstack_top dd ?
    _dstack_top dd ?
    ends
    macro PICOVM_CTX ip, dssz, rssz, rstop, dstop, rsb, dsb { PICOVM_CONTEXT dssz, ip, dsb, rssz, rsb, rstop, dstop }
     
    PICOVM_FNC_STEP = 0
    PICOVM_FNC_DSPOP = 1
    PICOVM_FNC_RUN = 2
    PICOVM_FNC_RSPOP = 3
    PICOVM_FNC_DSPUSH = 4
    PICOVM_FNC_RSPUSH = 5
    PICOVM_FNC_DEPTH = 6
     
    PICOVM_ADD_OPCODE equ 0x0
    PICOVM_PICK_OPCODE equ 0x1
    PICOVM_NOT_OPCODE equ 0x2
    PICOVM_STOREW_OPCODE equ 0x3
    PICOVM_LOADCW_OPCODE equ 0x4
    PICOVM_AND_OPCODE equ 0x5
    PICOVM_OVER_OPCODE equ 0x6
    PICOVM_DUP_OPCODE equ 0x7
    PICOVM_LOADCB_OPCODE equ 0x8
    PICOVM_XOR_OPCODE equ 0x9
    PICOVM_ROLL_OPCODE equ 0xA
    PICOVM_CALLN_OPCODE equ 0xB
    PICOVM_LOADCD_OPCODE equ 0xC
    PICOVM_CALLA_OPCODE equ 0xD
    PICOVM_JMPR_OPCODE equ 0xE
    PICOVM_SHR_OPCODE equ 0xF
    PICOVM_BELOW_OPCODE equ 0x10
    PICOVM_SHL_OPCODE equ 0x11
    PICOVM_FETCHD_OPCODE equ 0x12
    PICOVM_SUB_OPCODE equ 0x13
    PICOVM_ROT_OPCODE equ 0x14
    PICOVM_RET_OPCODE equ 0x15
    PICOVM_STORED_OPCODE equ 0x16
    PICOVM_DROP_OPCODE equ 0x17
    PICOVM_OR_OPCODE equ 0x18
    PICOVM_ROR_OPCODE equ 0x19
    PICOVM_EQ_OPCODE equ 0x1A
    PICOVM_ROL_OPCODE equ 0x1B
    PICOVM_ABOVE_OPCODE equ 0x1C
    PICOVM_SWAP_OPCODE equ 0x1D
    PICOVM_CALLR_OPCODE equ 0x1E
    PICOVM_FETCHW_OPCODE equ 0x1F
    PICOVM_MOD_OPCODE equ 0x20
    PICOVM_STOREB_OPCODE equ 0x21
    PICOVM_JMPC_OPCODE equ 0x22
    PICOVM_DIV_OPCODE equ 0x23
    PICOVM_MUL_OPCODE equ 0x24
    PICOVM_FETCHB_OPCODE equ 0x25
    PICOVM_JMPA_OPCODE equ 0x26
    PICOVM_HLT_OPCODE equ 0xFF
     
    PICOVM_ERR_NONE equ 0
    PICOVM_ERR_DSOVERFLOW equ -1
    PICOVM_ERR_DSUNDERFLOW equ -2
    PICOVM_ERR_RSOVERFLOW equ -4
    PICOVM_ERR_RSUNDERFLOW equ -5
    PICOVM_ERR_UNKNOWNFNC equ -6
    PICOVM_ERR_UNKNOWNCMD equ -7
     
    macro PICOVM_CMD cmd, n {
    if cmd eq _LOADCW
    db PICOVM##cmd##_OPCODE
    dw n and 0xffff
    else if cmd eq _LOADCD
    db PICOVM##cmd##_OPCODE
    dd n and 0xffffffff
    else if cmd eq _LOADCB
    db PICOVM##cmd##_OPCODE
    db n and 0xff
    else
    db PICOVM##cmd##_OPCODE
    end if
    }
     
    macro PICOVM_COMMAND_ENTRY link, sz, dsinp, dsoutp {
    dw ((link-__COMMANDS_BEGIN__) shl 0x6) + (sz and 0x7) + ((dsinp and 0x3) shl 0x3) + ((dsoutp and 0x1) shl 0x5)
    }
picovm.inc

Code: [Select]
    format binary
    use32
    org 0x0
     
    include '%FASMINC%\WIN32A.INC'
    include 'picovm.inc'
     
    __VM_BEGIN__:
    pusha
    call .delta
    .delta:
    sub DWord [esp], __VM_BEGIN__.delta - __VM_BEGIN__
    pop ebp
    cmp eax, 0x6
    ja .err
    call .fnc
     
    db __STEP__
    db __DSPOP__
    db __RUN__
    db __RSPOP__
    db __DSPUSH__
    db __RSPUSH__
    db __DEPTH__
     
    .fnc:
    pop ecx
    movzx ecx, Byte [ecx+eax]
    add ecx, ebp
    call ecx
    jmp short _save_eax_edx_stack_up
    .err:
    mov edx, PICOVM_ERR_UNKNOWNFNC
    jmp short __RSPUSH__.err
     
    __RSPUSH__:
    pusha
    mov esi, edx
    call __DEPTH__
    movzx ecx, [ebx+PICOVM_CONTEXT._rstack_size]
    cmp edx, ecx
    jb .ok
    mov edx, PICOVM_ERR_RSOVERFLOW
    .err:
    stc
    .up:
    mov eax, edx
    jmp short _save_eax_edx_stack_up
    .ok:
    mov ecx, [ebx+PICOVM_CONTEXT._rstack_top]
    mov [ecx], esi
    add [ebx+PICOVM_CONTEXT._rstack_top], 0x4
    xor edx, edx
    clc
    jmp short .up
     
    __RSPOP__:
    pusha
    call __DEPTH__
    test edx, edx
    jnz .ok
    mov edx, PICOVM_ERR_RSUNDERFLOW
    jmp short __RSPUSH__.err
    .ok:
    mov ecx, [ebx+PICOVM_CONTEXT._rstack_top]
    mov eax, [ecx-0x4]
    sub [ebx+PICOVM_CONTEXT._rstack_top], 0x4
    xor edx, edx
    clc
    _save_eax_edx_stack_up:
    jmp short _save_eax_edx_stack
     
    __DSPOP__:
    xor edx, edx
    xor eax, eax
    inc eax
    call __DSCheckInpOutp__
    jc .err
    mov ecx, [ebx+PICOVM_CONTEXT._dstack_top]
    mov eax, [ecx-0x4]
    sub [ebx+PICOVM_CONTEXT._dstack_top], 0x4
    clc
    ret
    .err:
    xchg edx, eax
    xor eax, eax
    stc
    ret
     
    __RUN__:
    test edx, edx
    jz .up
    mov [ebx+PICOVM_CONTEXT._instruction_pointer], edx
    .up:
    mov edx, [ebx+PICOVM_CONTEXT._instruction_pointer]
    cmp Byte [edx], PICOVM_HLT_OPCODE
    jz .ok
    call __STEP__
    ; pushf
    ; pusha
    ; call __DEPTH__
    ; popa
    ; popf
    jnc .up
    ret
    .ok:
    xchg edx, eax
    xor eax, eax
    ret
     
    __DSPUSH__:
    xor eax, eax
    inc ah
    call __DSCheckInpOutp__
    jnc .ok
    mov eax, edx
    ret
    .ok:
    mov ecx, [ebx+PICOVM_CONTEXT._dstack_top]
    mov DWord [ecx], edx
    add [ebx+PICOVM_CONTEXT._dstack_top], 0x4
    xor edx, edx
    ret
     
    __DEPTH__:
    pusha
    mov eax, [ebx+PICOVM_CONTEXT._dstack_top]
    mov edx, [ebx+PICOVM_CONTEXT._rstack_top]
    sub eax, [ebx+PICOVM_CONTEXT._dstack_begin]
    shr eax, 0x2
    sub edx, [ebx+PICOVM_CONTEXT._rstack_begin]
    shr edx, 0x2
    clc
    _save_eax_edx_stack:
    mov DWord [esp+0x14], edx
    _save_eax_stack:
    mov DWord [esp+0x1C], eax
    popa
    ret
     
    __STEP__:
    pusha
    xor eax, eax
    push eax
    mov esi, [ebx+PICOVM_CONTEXT._instruction_pointer]
    lea edi, [ebp+cmdsTable]
    movzx ecx, Byte [esi]
    mov eax, ecx
    shl eax, 0x1
    add edi, eax
    push edi
    movzx eax, Byte [edi]
    and al, 0x3F
    shl eax, 0x3
    shr al, 0x6
    call __DSCheckInpOutp__
    jc .err
    movzx eax, Word [edi]
    shr eax, 0x6
    add eax, ebp
    add eax, __COMMANDS_BEGIN__
    push ebp
    add DWord [esp], __STEP__.return
    push eax
    mov edi, [ebx+PICOVM_CONTEXT._dstack_top]
    mov edx, DWord [edi-0x8]
    mov eax, DWord [edi-0x4]
    ret
    .return:
    pop edx
    mov eax, DWord [esp]
    test eax, eax
    jnz short .err
    mov ebx, DWord [esp+0x14]
    movzx edx, Byte [edx]
    and edx, 0x7
    jz short .end
    mov esi, [ebx+PICOVM_CONTEXT._instruction_pointer]
    add esi, edx
    xor edx, edx
    jmp short .end
    .err:
    xchg edx, eax
    xchg eax, esi
    stc
    .end:
    mov eax, esi
    pop ecx
    mov [ebx+PICOVM_CONTEXT._dstack_top], edi
    mov [ebx+PICOVM_CONTEXT._instruction_pointer], esi
    _save_eax_edx_stack_down:
    jmp short _save_eax_edx_stack
     
    __DSCheckInpOutp__:
    pusha
    xor edi, edi
    mov edx, eax
    shr edx, 0x8
    xchg esi, eax
    and esi, 0xff
    call __DEPTH__
    cmp eax, esi
    jnl .outp
    dec edi
    jmp short .err
    .outp:
    movzx esi, Byte [ebx+PICOVM_CONTEXT._dstack_size]
    sub esi, eax
    cmp esi, edx
    jnl .ok
    dec edi
    dec edi
    .err:
    stc
    jmp short .end
    .ok:
    clc
    .end:
    xchg edi, eax
    jmp _save_eax_stack
    __COMMANDS_BEGIN__:
     
    _calln_:
    call eax
    ret
     
    ;_mrtd_:
    ; call _crtd_
    ; sub [ebx + PICOVM_CONTEXT._rstack_top], 0x4
    ; ret
     
    _stored_:
    mov [eax], edx
    _drop2:
    sub edi, 0x8
    ret
     
    _storew_:
    mov Word [eax], dx
    jmp short _drop2
     
    _storeb_:
    mov Byte [eax], dl
    jmp short _drop2
     
    _jmpa_:
    mov esi, eax
    jmp short _drop_
     
    _jmpr_:
    add esi, eax
    jmp short _drop_
     
    _jmpc_:
    test edx, edx
    jnz short _jmpc_not
    add esi, eax
    jmp short _drop2
     
    _jmpc_not:
    inc esi
    jmp short _drop2
     
    _over_:
    xchg ecx, edx
    ; jmp short _save_ecx_up1
     
    ;_depthr_:
    ; call __DEPTH__
    ; xchg edx, eax
    ; jmp short _save_ecx_up1
     
    ;_depthd_:
    ; call __DEPTH__
    ; xchg ecx, eax
    _save_ecx_up1:
    mov [edi], ecx
    add edi, 0x4
    ret
     
    _loadcb_:
    movzx ecx, Byte [esi+0x1]
    jmp short _save_ecx_up1
    _loadcw_:
    movzx ecx, Word [esi+0x1]
    jmp short _save_ecx_up1
    _loadcd_:
    mov ecx, [esi+0x1]
    jmp short _save_ecx_up1
     
    _dup_:
    xchg ecx, eax
    jmp short _save_ecx_up1
     
    _drop_:
     
    sub edi, 0x4
    ret
     
    ;_mdtr_:
    ; call _cdtr_
    ; jmp short _drop_
     
    _calla_:
    mov ecx, eax
    mov edx, esi
    inc edx
    call __RSPUSH__
    jc _err_edx
    mov esi, ecx
    jmp short _drop_
     
    _callr_:
    mov ecx, eax
    mov edx, esi
    inc edx
    call __RSPUSH__
    jc _err_edx
    add esi, ecx
    jmp short _drop_
     
    _mod_:
    mov ecx, eax
    xchg eax, edx
    xor edx, edx
    div ecx
    _save_edx_down1:
    mov [edi-0x8], edx
    jmp short _drop_
     
    _above_:
    xor ecx, ecx
    cmp eax, edx
    ja short _save_ecx_down1
    dec ecx
    _save_ecx_down1:
    mov [edi-0x8], ecx
    jmp short _drop_
     
    _below_:
    xor ecx, ecx
    cmp eax, edx
    jb short _save_ecx_down1
    dec ecx
    jmp short _save_ecx_down1
     
    _add_:
    add eax, edx
    jmp short _save_eax_down1
     
    _sub_:
    sub edx, eax
    jmp short _save_edx_down1
     
    _mul_:
    mul edx
    jmp short _save_eax_down1
     
    _xor_:
    xor eax, edx
    jmp short _save_eax_down1
     
    _shr_:
    xchg eax, edx
    xchg ecx, edx
    shr eax, cl
    jmp short _save_eax_down1
     
    _ror_:
    xchg eax, edx
    xchg ecx, edx
    ror eax, cl
    jmp short _save_eax_down1
     
    _shl_:
    xchg eax, edx
    xchg ecx, edx
    shl eax, cl
    jmp short _save_eax_down1
     
    _eq_:
    xor ecx, ecx
    cmp eax, edx
    jnz _save_ecx_down1
    dec ecx
    jmp short _save_ecx_down1
     
    ;_sar_:
    ; xchg eax, ecx
    ; sar edx, cl
    ; xchg edx, eax
    ; jmp short _save_eax_down1
     
    _not_:
    not eax
    jmp short _save_eax
     
    _rot_:
    mov ecx, [edi-0xC]
    mov [edi-0xC], edx
    mov [edi-0x8], eax
    _save_ecx_d:
    mov [edi-0x4], ecx
    ret
     
    ;_sal_:
    ; xchg eax, ecx
    ; sal edx, cl
    ; xchg edx, eax
    ; jmp short _save_eax_down1
     
    ;_neg_:
    ; neg eax
    ; jmp short _save_eax
     
    _div_:
    mov ecx, eax
    xchg eax, edx
    xor edx, edx
    div ecx
    _save_eax_down1:
    mov [edi-0x8], eax
    jmp _drop_
     
    _rol_:
    xchg eax, edx
    xchg ecx, edx
    rol eax, cl
    jmp short _save_eax_down1
     
    _and_:
    and eax, edx
    jmp short _save_eax_down1
     
    _or_:
    or eax, edx
    jmp short _save_eax_down1
     
    _swap_:
    xchg eax, edx
    _save_eax_edx:
    mov [edi-0x8], edx
    _save_eax:
    xchg ecx, eax
    jmp short _save_ecx
    _fetchb_:
    movzx eax, Byte [eax]
    jmp short _save_eax
     
    _fetchw_:
    movzx eax, Word [eax]
    jmp short _save_eax
    _fetchd_:
    mov eax, [eax]
    jmp short _save_eax
     
    ;_esb_:
    ; cbw
    ;_esw_:
    ; cwde
    ; jmp short _save_eax
     
    _save_ecx:
    mov [edi-0x4], ecx
    ret
     
    _pick_:
    inc eax
    inc eax
    mov edx, eax
    call __DSCheckInpOutp__
    jc _err_
    shl edx, 0x2
    mov eax, edi
    sub eax, edx
    push DWord [eax]
    pop DWord [edi-0x4]
    ret
     
    _roll_:
    mov edx, eax
    inc eax
    inc eax
    call __DSCheckInpOutp__
    jc _err_
    pusha
    mov ecx, edx
    xchg esi, edi
    mov ebx, ecx
    inc ebx
    shl ebx, 0x2
    sub esi, ebx
    lea edi, [esi-0x4]
    push DWord [edi]
    cld
    rep movsd
    pop DWord [edi]
    popa
    sub edi, 0x4
    ret
     
    _drop_d:
    sub edi, 0x4
    ret
     
    _ret_:
    call __RSPOP__
    jc _err_edx
    mov esi, eax
    ret
     
    ;_cdtr_:
    ; mov edx, eax
    ; call __RSPUSH__
    ; jc short _err_edx
    ; ret
     
    ;_crtd_:
    ; mov edx, [ebx + PICOVM_CONTEXT._rstack_top]
    ; mov eax, [ebx + PICOVM_CONTEXT._rstack_begin]
    ; cmp edx, eax
    ; jbe .err
    ; mov ecx, [edx-0x4]
    ; jmp _save_ecx_up1
    ;.err:
    ; mov eax, PICOVM_ERR_RSUNDERFLOW
    ; jmp _err_
    _err_edx:
    xchg eax, edx
    _err_:
    mov [esp+0x8], eax
    ret
     
     
    cmdsTable:
    PICOVM_COMMAND_ENTRY _add_, 0x1, 0x2, 0x0
    PICOVM_COMMAND_ENTRY _pick_, 0x1, 0x2, 0x0
    PICOVM_COMMAND_ENTRY _not_, 0x1, 0x1, 0x0
    PICOVM_COMMAND_ENTRY _storew_, 0x1, 0x2, 0x0
    PICOVM_COMMAND_ENTRY _loadcw_, 0x3, 0x0, 0x1
    PICOVM_COMMAND_ENTRY _and_, 0x1, 0x2, 0x0
    PICOVM_COMMAND_ENTRY _over_, 0x1, 0x2, 0x0
    PICOVM_COMMAND_ENTRY _dup_, 0x1, 0x1, 0x1
    PICOVM_COMMAND_ENTRY _loadcb_, 0x2, 0x0, 0x1
    PICOVM_COMMAND_ENTRY _xor_, 0x1, 0x2, 0x0
    PICOVM_COMMAND_ENTRY _roll_, 0x1, 0x2, 0x0
    PICOVM_COMMAND_ENTRY _calln_, 0x0, 0x1, 0x0
    PICOVM_COMMAND_ENTRY _loadcd_, 0x5, 0x0, 0x1
    PICOVM_COMMAND_ENTRY _calla_, 0x0, 0x1, 0x0
    PICOVM_COMMAND_ENTRY _jmpr_, 0x0, 0x1, 0x0
    PICOVM_COMMAND_ENTRY _shr_, 0x1, 0x2, 0x0
    PICOVM_COMMAND_ENTRY _below_, 0x1, 0x2, 0x0
    PICOVM_COMMAND_ENTRY _shl_, 0x1, 0x2, 0x0
    PICOVM_COMMAND_ENTRY _fetchd_, 0x1, 0x1, 0x0
    PICOVM_COMMAND_ENTRY _sub_, 0x1, 0x2, 0x0
    PICOVM_COMMAND_ENTRY _rot_, 0x1, 0x3, 0x0
    PICOVM_COMMAND_ENTRY _ret_, 0x0, 0x0, 0x0
    PICOVM_COMMAND_ENTRY _stored_, 0x1, 0x2, 0x0
    PICOVM_COMMAND_ENTRY _drop_, 0x1, 0x1, 0x0
    PICOVM_COMMAND_ENTRY _or_, 0x1, 0x2, 0x0
    PICOVM_COMMAND_ENTRY _ror_, 0x1, 0x2, 0x0
    PICOVM_COMMAND_ENTRY _eq_, 0x1, 0x2, 0x0
    PICOVM_COMMAND_ENTRY _rol_, 0x1, 0x2, 0x0
    PICOVM_COMMAND_ENTRY _above_, 0x1, 0x2, 0x0
    PICOVM_COMMAND_ENTRY _swap_, 0x1, 0x2, 0x0
    PICOVM_COMMAND_ENTRY _callr_, 0x0, 0x1, 0x0
    PICOVM_COMMAND_ENTRY _fetchw_, 0x1, 0x1, 0x0
    PICOVM_COMMAND_ENTRY _mod_, 0x1, 0x2, 0x0
    PICOVM_COMMAND_ENTRY _storeb_, 0x1, 0x2, 0x0
    PICOVM_COMMAND_ENTRY _jmpc_, 0x0, 0x2, 0x0
    PICOVM_COMMAND_ENTRY _div_, 0x1, 0x2, 0x0
    PICOVM_COMMAND_ENTRY _mul_, 0x1, 0x2, 0x0
    PICOVM_COMMAND_ENTRY _fetchb_, 0x1, 0x1, 0x0
    PICOVM_COMMAND_ENTRY _jmpa_, 0x0, 0x1, 0x0
Characteristics of VM stored in file picovm.settings.json (JSON format):
 
Code: [Select]
{"date":null,"cmds":["add","pick","not","storew","loadcw","and","over","dup","loadcb","xor","roll","calln","loadcd","calla","jmpr","shr","below","shl","fetchd","sub","rot","ret","stored","drop","or","ror","eq","rol","above","swap","callr","fetchw","mod","storeb","jmpc","div","mul","fetchb","jmpa"],"consts":["STEP","DSPOP","RUN","RSPOP","DSPUSH","RSPUSH","DEPTH"]}
Virtual machines generator (written in JS):
Code: [Select]
    var _ = require ('underscore');
    var fs = require ('fs');
     
    Number.prototype.toHex = function() {
    return('0x'+this.toString(16).toUpperCase());};
     
    var fncs = ['RUN', 'STEP', 'DEPTH', 'RSPOP', 'RSPUSH', 'DSPOP', 'DSPUSH'];
    var cmds_array = [];
    var picovm_inc_end = '\
    PICOVM_ERR_NONE equ 0\n\
    PICOVM_ERR_DSOVERFLOW equ -1\n\
    PICOVM_ERR_DSUNDERFLOW equ -2\n\
    PICOVM_ERR_RSOVERFLOW equ -4\n\
    PICOVM_ERR_RSUNDERFLOW equ -5\n\
    PICOVM_ERR_UNKNOWNFNC equ -6\n\
    PICOVM_ERR_UNKNOWNCMD equ -7\n\n\
    macro PICOVM_CMD cmd, n {\n\
    if cmd eq _LOADCW\n\
    db PICOVM##cmd##_OPCODE\n\
    dw n and 0xffff\n\
    else if cmd eq _LOADCD\n\
    db PICOVM##cmd##_OPCODE\n\
    dd n and 0xffffffff\n\
    else if cmd eq _LOADCB\n\
    db PICOVM##cmd##_OPCODE\n\
    db n and 0xff\n\
    else\n\
    db PICOVM##cmd##_OPCODE\n\
    end if\n\
    }\n\n\
    macro PICOVM_COMMAND_ENTRY link, sz, dsinp, dsoutp {\n\
    dw ((link-__COMMANDS_BEGIN__) shl 0x6) + (sz and 0x7) + ((dsinp and 0x3) shl 0x3) + ((dsoutp and 0x1) shl 0x5)\n\
    }\n\n';
     
    var picovm_asm_begin = 'format binary\n\
    use32\n\
    org 0x0\n\n\
    include \'%FASMINC%\\WIN32A.INC\'\n\
    include \'picovm.inc\'\n\n\
    __VM_BEGIN__:\n\
    pusha\n\
    call .delta\n\
    .delta:\n\
    sub DWord [esp], __VM_BEGIN__.delta - __VM_BEGIN__\n\
    pop ebp\n\
    cmp eax, 0x6\n\
    ja .err\n\
    call .fnc\n';
     
    var picovm_asm_body = '.fnc:\n\
    pop ecx\n\
    movzx ecx, Byte [ecx+eax]\n\
    add ecx, ebp\n\
    call ecx\n\
    jmp short _save_eax_edx_stack_up\n\
    .err:\n\
    mov edx, PICOVM_ERR_UNKNOWNFNC\n\
    jmp short __RSPUSH__.err\n\n\
    __RSPUSH__:\n\
    pusha\n\
    mov esi, edx\n\
    call __DEPTH__\n\
    movzx ecx, [ebx+PICOVM_CONTEXT._rstack_size]\n\
    cmp edx, ecx\n\
    jb .ok\n\
    mov edx, PICOVM_ERR_RSOVERFLOW\n\
    .err:\n\
    stc\n\
    .up:\n\
    mov eax, edx\n\
    jmp short _save_eax_edx_stack_up\n\
    .ok: \n\
    mov ecx, [ebx+PICOVM_CONTEXT._rstack_top]\n\
    mov [ecx], esi\n\
    add [ebx+PICOVM_CONTEXT._rstack_top], 0x4\n\
    xor edx, edx\n\
    clc\n\
    jmp short .up\n\n\
    __RSPOP__:\n\
    pusha\n\
    call __DEPTH__\n\
    test edx, edx\n\
    jnz .ok\n\
    mov edx, PICOVM_ERR_RSUNDERFLOW\n\
    jmp short __RSPUSH__.err\n\
    .ok: \n\
    mov ecx, [ebx+PICOVM_CONTEXT._rstack_top]\n\
    mov eax, [ecx-0x4]\n\
    sub [ebx+PICOVM_CONTEXT._rstack_top], 0x4\n\
    xor edx, edx\n\
    clc\n\
    _save_eax_edx_stack_up:\n\
    jmp short _save_eax_edx_stack\n\n\
    __DSPOP__:\n\
    xor edx, edx\n\
    xor eax, eax\n\
    inc eax\n\
    call __DSCheckInpOutp__\n\
    jc .err\n\
    mov ecx, [ebx+PICOVM_CONTEXT._dstack_top]\n\
    mov eax, [ecx-0x4]\n\
    sub [ebx+PICOVM_CONTEXT._dstack_top], 0x4\n\
    clc\n\
    ret\n\
    .err:\n\
    xchg edx, eax\n\
    xor eax, eax\n\
    stc\n\
    ret\n\n\
    __RUN__:\n\
    test edx, edx\n\
    jz .up\n\
    mov [ebx+PICOVM_CONTEXT._instruction_pointer], edx\n\
    .up:\n\
    mov edx, [ebx+PICOVM_CONTEXT._instruction_pointer]\n\
    cmp Byte [edx], PICOVM_HLT_OPCODE\n\
    jz .ok\n\
    call __STEP__\n\
    ; pushf\n\
    ; pusha\n\
    ; call __DEPTH__\n\
    ; popa\n\
    ; popf\n\
    jnc .up\n\
    ret\n\
    .ok: \n\
    xchg edx, eax\n\
    xor eax, eax\n\
    ret\n\n\
    __DSPUSH__:\n\
    xor eax, eax\n\
    inc ah\n\
    call __DSCheckInpOutp__\n\
    jnc .ok\n\
    mov eax, edx\n\
    ret\n\
    .ok:\n\
    mov ecx, [ebx+PICOVM_CONTEXT._dstack_top]\n\
    mov DWord [ecx], edx\n\
    add [ebx+PICOVM_CONTEXT._dstack_top], 0x4\n\
    xor edx, edx\n\
    ret\n\n\
    __DEPTH__:\n\
    pusha\n\
    mov eax, [ebx+PICOVM_CONTEXT._dstack_top]\n\
    mov edx, [ebx+PICOVM_CONTEXT._rstack_top]\n\
    sub eax, [ebx+PICOVM_CONTEXT._dstack_begin]\n\
    shr eax, 0x2\n\
    sub edx, [ebx+PICOVM_CONTEXT._rstack_begin]\n\
    shr edx, 0x2\n\
    clc\n\
    _save_eax_edx_stack:\n\
    mov DWord [esp+0x14], edx\n\
    _save_eax_stack:\n\
    mov DWord [esp+0x1C], eax\n\
    popa\n\
    ret\n\n\
    __STEP__:\n\
    pusha\n\
    xor eax, eax\n\
    push eax\n\
    mov esi, [ebx+PICOVM_CONTEXT._instruction_pointer]\n\
    lea edi, [ebp+cmdsTable]\n\
    movzx ecx, Byte [esi]\n\
    mov eax, ecx\n\
    shl eax, 0x1\n\
    add edi, eax\n\
    push edi\n\
    movzx eax, Byte [edi]\n\
    and al, 0x3F\n\
    shl eax, 0x3\n\
    shr al, 0x6\n\
    call __DSCheckInpOutp__\n\
    jc .err\n\
    movzx eax, Word [edi]\n\
    shr eax, 0x6\n\
    add eax, ebp\n\
    add eax, __COMMANDS_BEGIN__\n\
    push ebp\n\
    add DWord [esp], __STEP__.return\n\
    push eax\n\
    mov edi, [ebx+PICOVM_CONTEXT._dstack_top]\n\
    mov edx, DWord [edi-0x8]\n\
    mov eax, DWord [edi-0x4]\n\
    ret\n\
    .return:\n\
    pop edx\n\
    mov eax, DWord [esp]\n\
    test eax, eax\n\
    jnz short .err\n\
    mov ebx, DWord [esp+0x14]\n\
    movzx edx, Byte [edx]\n\
    and edx, 0x7\n\
    jz short .end\n\
    mov esi, [ebx+PICOVM_CONTEXT._instruction_pointer]\n\
    add esi, edx\n\
    xor edx, edx\n\
    jmp short .end\n\
    .err:\n\
    xchg edx, eax\n\
    xchg eax, esi\n\
    stc\n\
    .end:\n\
    mov eax, esi\n\
    pop ecx\n\
    mov [ebx+PICOVM_CONTEXT._dstack_top], edi\n\
    mov [ebx+PICOVM_CONTEXT._instruction_pointer], esi\n\
    _save_eax_edx_stack_down:\n\
    jmp short _save_eax_edx_stack\n\n\
    __DSCheckInpOutp__:\n\
    pusha\n\
    xor edi, edi\n\
    mov edx, eax\n\
    shr edx, 0x8\n\
    xchg esi, eax\n\
    and esi, 0xff\n\
    call __DEPTH__\n\
    cmp eax, esi\n\
    jnl .outp\n\
    dec edi\n\
    jmp short .err\n\
    .outp:\n\
    movzx esi, Byte [ebx+PICOVM_CONTEXT._dstack_size]\n\
    sub esi, eax\n\
    cmp esi, edx\n\
    jnl .ok\n\
    dec edi\n\
    dec edi\n\
    .err:\n\
    stc\n\
    jmp short .end\n\
    .ok:\n\
    clc\n\
    .end:\n\
    xchg edi, eax\n\
    jmp _save_eax_stack\n\
    __COMMANDS_BEGIN__:\n\n\
    _calln_:\n\
    call eax\n\
    ret\n\n\
    ;_mrtd_:\n\
    ; call _crtd_\n\
    ; sub [ebx + PICOVM_CONTEXT._rstack_top], 0x4\n\
    ; ret\n\n\
    _stored_:\n\
    mov [eax], edx\n\
    _drop2:\n\
    sub edi, 0x8\n\
    ret\n\n\
    _storew_:\n\
    mov Word [eax], dx\n\
    jmp short _drop2\n\n\
    _storeb_:\n\
    mov Byte [eax], dl\n\
    jmp short _drop2\n\n\
    _jmpa_:\n\
    mov esi, eax\n\
    jmp short _drop_\n\n\
    _jmpr_:\n\
    add esi, eax\n\
    jmp short _drop_\n\n\
    _jmpc_:\n\
    test edx, edx\n\
    jnz short _jmpc_not\n\
    add esi, eax\n\
    jmp short _drop2\n\n\
    _jmpc_not:\n\
    inc esi\n\
    jmp short _drop2\n\n\
    _over_:\n\
    xchg ecx, edx\n\
    ; jmp short _save_ecx_up1\n\n\
    ;_depthr_:\n\
    ; call __DEPTH__\n\
    ; xchg edx, eax\n\
    ; jmp short _save_ecx_up1\n\n\
    ;_depthd_:\n\
    ; call __DEPTH__\n\
    ; xchg ecx, eax\n\
    _save_ecx_up1:\n\
    mov [edi], ecx\n\
    add edi, 0x4\n\
    ret\n\n\
    _loadcb_:\n\
    movzx ecx, Byte [esi+0x1]\n\
    jmp short _save_ecx_up1\n\
    _loadcw_:\n\
    movzx ecx, Word [esi+0x1]\n\
    jmp short _save_ecx_up1\n\
    _loadcd_:\n\
    mov ecx, [esi+0x1]\n\
    jmp short _save_ecx_up1\n\n\
    _dup_:\n\
    xchg ecx, eax\n\
    jmp short _save_ecx_up1\n\n\
    _drop_:\n\n\
    sub edi, 0x4\n\
    ret\n\n\
    ;_mdtr_:\n\
    ; call _cdtr_\n\
    ; jmp short _drop_\n\n\
    _calla_:\n\
    mov ecx, eax\n\
    mov edx, esi\n\
    inc edx\n\
    call __RSPUSH__\n\
    jc _err_edx\n\
    mov esi, ecx\n\
    jmp short _drop_\n\n\
    _callr_:\n\
    mov ecx, eax\n\
    mov edx, esi\n\
    inc edx\n\
    call __RSPUSH__\n\
    jc _err_edx\n\
    add esi, ecx\n\
    jmp short _drop_\n\n\
    _mod_:\n\
    mov ecx, eax\n\
    xchg eax, edx\n\
    xor edx, edx\n\
    div ecx\n\
    _save_edx_down1:\n\
    mov [edi-0x8], edx\n\
    jmp short _drop_\n\n\
    _above_:\n\
    xor ecx, ecx\n\
    cmp eax, edx\n\
    ja short _save_ecx_down1\n\
    dec ecx\n\
    _save_ecx_down1:\n\
    mov [edi-0x8], ecx\n\
    jmp short _drop_\n\n\
    _below_:\n\
    xor ecx, ecx\n\
    cmp eax, edx\n\
    jb short _save_ecx_down1\n\
    dec ecx\n\
    jmp short _save_ecx_down1\n\n\
    _add_:\n\
    add eax, edx\n\
    jmp short _save_eax_down1\n\n\
    _sub_:\n\
    sub edx, eax\n\
    jmp short _save_edx_down1\n\n\
    _mul_:\n\
    mul edx\n\
    jmp short _save_eax_down1\n\n\
    _xor_:\n\
    xor eax, edx\n\
    jmp short _save_eax_down1\n\n\
    _shr_:\n\
    xchg eax, edx\n\
    xchg ecx, edx\n\
    shr eax, cl\n\
    jmp short _save_eax_down1\n\n\
    _ror_:\n\
    xchg eax, edx\n\
    xchg ecx, edx\n\
    ror eax, cl\n\
    jmp short _save_eax_down1\n\n\
    _shl_:\n\
    xchg eax, edx\n\
    xchg ecx, edx\n\
    shl eax, cl\n\
    jmp short _save_eax_down1\n\n\
    _eq_:\n\
    xor ecx, ecx\n\
    cmp eax, edx\n\
    jnz _save_ecx_down1\n\
    dec ecx\n\
    jmp short _save_ecx_down1\n\n\
    ;_sar_:\n\
    ; xchg eax, ecx\n\
    ; sar edx, cl\n\
    ; xchg edx, eax\n\
    ; jmp short _save_eax_down1\n\n\
    _not_:\n\
    not eax\n\
    jmp short _save_eax\n\n\
    _rot_:\n\
    mov ecx, [edi-0xC]\n\
    mov [edi-0xC], edx\n\
    mov [edi-0x8], eax\n\
    _save_ecx_d:\n\
    mov [edi-0x4], ecx\n\
    ret\n\n\
    ;_sal_:\n\
    ; xchg eax, ecx\n\
    ; sal edx, cl\n\
    ; xchg edx, eax\n\
    ; jmp short _save_eax_down1\n\n\
    ;_neg_:\n\
    ; neg eax\n\
    ; jmp short _save_eax\n\n\
    _div_:\n\
    mov ecx, eax\n\
    xchg eax, edx\n\
    xor edx, edx\n\
    div ecx\n\
    _save_eax_down1:\n\
    mov [edi-0x8], eax\n\
    jmp _drop_\n\n\
    _rol_:\n\
    xchg eax, edx\n\
    xchg ecx, edx\n\
    rol eax, cl\n\
    jmp short _save_eax_down1\n\n\
    _and_:\n\
    and eax, edx\n\
    jmp short _save_eax_down1\n\n\
    _or_:\n\
    or eax, edx\n\
    jmp short _save_eax_down1\n\n\
    _swap_:\n\
    xchg eax, edx\n\
    _save_eax_edx:\n\
    mov [edi-0x8], edx\n\
    _save_eax:\n\
    xchg ecx, eax\n\
    jmp short _save_ecx\n\
    _fetchb_:\n\
    movzx eax, Byte [eax]\n\
    jmp short _save_eax\n\n\
    _fetchw_:\n\
    movzx eax, Word [eax]\n\
    jmp short _save_eax\n\
    _fetchd_:\n\
    mov eax, [eax]\n\
    jmp short _save_eax\n\n\
    ;_esb_:\n\
    ; cbw\n\
    ;_esw_:\n\
    ; cwde\n\
    ; jmp short _save_eax\n\n\
    _save_ecx:\n\
    mov [edi-0x4], ecx\n\
    ret\n\n\
    _pick_:\n\
    inc eax\n\
    inc eax\n\
    mov edx, eax\n\
    call __DSCheckInpOutp__\n\
    jc _err_\n\
    shl edx, 0x2\n\
    mov eax, edi\n\
    sub eax, edx\n\
    push DWord [eax]\n\
    pop DWord [edi-0x4]\n\
    ret\n\n\
    _roll_:\n\
    mov edx, eax\n\
    inc eax\n\
    inc eax\n\
    call __DSCheckInpOutp__\n\
    jc _err_\n\
    pusha\n\
    mov ecx, edx\n\
    xchg esi, edi\n\
    mov ebx, ecx\n\
    inc ebx\n\
    shl ebx, 0x2\n\
    sub esi, ebx\n\
    lea edi, [esi-0x4]\n\
    push DWord [edi]\n\
    cld\n\
    rep movsd\n\
    pop DWord [edi]\n\
    popa\n\
    sub edi, 0x4\n\
    ret\n\n\
    _drop_d:\n\
    sub edi, 0x4\n\
    ret\n\n\
    _ret_:\n\
    call __RSPOP__\n\
    jc _err_edx\n\
    mov esi, eax\n\
    ret\n\n\
    ;_cdtr_:\n\
    ; mov edx, eax\n\
    ; call __RSPUSH__\n\
    ; jc short _err_edx\n\
    ; ret\n\n\
    ;_crtd_:\n\
    ; mov edx, [ebx + PICOVM_CONTEXT._rstack_top]\n\
    ; mov eax, [ebx + PICOVM_CONTEXT._rstack_begin]\n\
    ; cmp edx, eax\n\
    ; jbe .err\n\
    ; mov ecx, [edx-0x4]\n\
    ; jmp _save_ecx_up1\n\
    ;.err:\n\
    ; mov eax, PICOVM_ERR_RSUNDERFLOW\n\
    ; jmp _err_\n\
    _err_edx:\n\
    xchg eax, edx\n\
    _err_:\n\
    mov [esp+0x8], eax\n\
    ret\n';
     
    var macroparams = [];
    var struc = 'struct PICOVM_CONTEXT\n';
    picovm_struc = _.shuffle(
    [['_dstack_top dd ?', 'dstop'],
    ['_dstack_begin dd ?', 'dsb'],
    ['_rstack_top dd ?', 'rstop'],
    ['_rstack_begin dd ?', 'rsb'],
    ['_instruction_pointer dd ?', 'ip'],
    ['_dstack_size db ?', 'dssz'],
    ['_rstack_size db ?', 'rssz']]);
    //picovm_struc+='';
    _.each(picovm_struc, function (a){
    struc+=a[0]+'\n';
    macroparams.push(a[1]);
    }, this);
    struc+='\nends';
    var macro = 'macro PICOVM_CTX ip, dssz, rssz, rstop, dstop, rsb, dsb { PICOVM_CONTEXT '+ macroparams.join(', ')+' }\n';
    var cmds = [
    ['fetchb', 0x1, 0x1, 0x0],
    ['fetchw', 0x1, 0x1, 0x0],
    ['fetchd', 0x1, 0x1, 0x0],
    ['storeb', 0x1, 0x2, 0x0],
    ['storew', 0x1, 0x2, 0x0],
    ['stored', 0x1, 0x2, 0x0],
    ['not', 0x1, 0x1, 0x0],
    ['or', 0x1, 0x2, 0x0],
    ['and', 0x1, 0x2, 0x0],
    ['xor', 0x1, 0x2, 0x0],
    ['loadcb', 0x2, 0x0, 0x1],
    ['loadcw', 0x3, 0x0, 0x1],
    ['loadcd', 0x5, 0x0, 0x1],
    ['rol', 0x1, 0x2, 0x0],
    ['ror', 0x1, 0x2, 0x0],
    ['shl', 0x1, 0x2, 0x0],
    ['shr', 0x1, 0x2, 0x0],
    ['eq', 0x1, 0x2, 0x0],
    ['above', 0x1, 0x2, 0x0],
    ['below', 0x1, 0x2, 0x0],
    ['drop',0x1, 0x1, 0x0],
    ['swap',0x1, 0x2, 0x0],
    ['over',0x1, 0x2, 0x0],
    ['pick',0x1, 0x2, 0x0],
    ['roll',0x1, 0x2, 0x0],
    ['add', 0x1, 0x2, 0x0],
    ['sub', 0x1, 0x2, 0x0],
    ['mul', 0x1, 0x2, 0x0],
    ['div', 0x1, 0x2, 0x0],
    ['mod', 0x1, 0x2, 0x0],
    ['rot', 0x1, 0x3, 0x0],
    ['dup', 0x1, 0x1, 0x1],
    ['jmpr', 0x0, 0x1, 0x0],
    ['jmpa', 0x0, 0x1, 0x0],
    ['jmpc', 0x0, 0x2, 0x0],
    ['calla', 0x0, 0x1, 0x0],
    ['callr', 0x0, 0x1, 0x0],
    ['calln', 0x0, 0x1, 0x0],
    ['ret', 0x0, 0x0, 0x0]];
     
    fncs=_.shuffle(fncs);
    cmds=_.shuffle(cmds);
    var vmconst = [];
    var fncs_inc = '';
    var fncs_asm = '';
    var cmds_inc = '';
    var cmds_asm = 'cmdsTable:\n';
    var i = 0;
    _.each (fncs, function(a) { fncs_inc += 'PICOVM_FNC_'+a+' = '+i+'\n'; fncs_asm += ' db __'+a+'__\n'; i++;}, this);
    i = 0;
    _.each (cmds, function(a) {
    cmds_inc += 'PICOVM_'+a[0].toUpperCase()+'_OPCODE equ '+i.toHex()+'\n';
    cmds_asm += ' PICOVM_COMMAND_ENTRY _'+a[0]+'_, '+a[1].toHex()+', '+a[2].toHex()+', '+a[3].toHex()+'\n';
    i++;}, this);
    cmds_inc += 'PICOVM_HLT_OPCODE equ 0xFF\n';
    var picovm_asm = picovm_asm_begin +'\n'+fncs_asm +'\n'+ picovm_asm_body + '\n\n'+cmds_asm;
    var picovm_inc = struc +'\n'+macro+'\n'+fncs_inc +'\n' + cmds_inc +'\n' + picovm_inc_end;
    var settings = JSON.stringify({date: null, cmds: _.pluck(cmds, 0), consts: fncs});
    fs.writeFile(process.argv[2]+'\\picovm.settings.json', settings);
    fs.writeFile(process.argv[2]+'\\picovm.asm', picovm_asm);
    fs.writeFile(process.argv[2]+'\\picovm.inc', picovm_inc);
Examples
 
For shorting source code I using next macros:
Code: [Select]
macro @ cmd, p {
  PICOVM_CMD cmd, p
}
Crypto algorithm RC4:
Code: [Select]
    ; [lpBuf, lpKey, dwBufLen, dwKeyLen, pS]
    RC4:
    @ _LOADCB, 0 ;B
    @ _DUP ;A
    @ _ROT
    @ _SWAP
    .for1_up:
    @ _DUP
    @ _LOADCW, 0x100;
    @ _EQ
    @ _NOT
    @ _LOADCD, .for1_down-.tofor1_down
    .tofor1_down:
    @ _JMPC
    @ _OVER
    @ _OVER
    @ _ADD
    @ _OVER
    @ _SWAP
    @ _STOREB
    @ _LOADCB, 0x1
    @ _ADD
    @ _LOADCD, .for1_up-.tofor1_up
    .tofor1_up:
    @ _JMPR
    .for1_down:
    @ _DROP
    @ _LOADCB, 0x0
    ;[lpBuf, lpKey, dwBufLen, dwKeyLen, B, pS, A=0]
    .for2_up:
    @ _DUP
    @ _LOADCW, 0x100
    @ _EQ
    @ _NOT
    @ _LOADCD, .for2_down-.tofor2_down
    .tofor2_down:
    @ _JMPC
    @ _OVER
    @ _OVER
    @ _ADD
    @ _FETCHB
    ;[lpBuf, lpKey, dwBufLen, dwKeyLen, B, pS, A=0, pS[A]]
    @ _LOADCB, 0x3
    @ _PICK
    @ _ADD
    ;[lpBuf, lpKey, dwBufLen, dwKeyLen, B, pS, A=0, pS[A]+B]
    @ _OVER
    @ _LOADCB, 0x5
    @ _PICK
    @ _MOD
    @ _LOADCB, 0x7
    @ _PICK
    @ _ADD
    @ _FETCHB
    ;[lpBuf, lpKey, dwBufLen, dwKeyLen, B, pS, A=0, pS[A]+B, lpKey [A % dwKeyLen]]
    @ _ADD
    @ _LOADCB, 0xFF
    @ _AND
    ;[lpBuf, lpKey, dwBufLen, dwKeyLen, B, pS, A=0, pS[A]+B+lpKey [A % dwKeyLen]]
    @ _LOADCB, 0x3
    @ _ROLL
    @ _DROP
    ;[lpBuf, lpKey, dwBufLen, dwKeyLen, pS, A, B]
    @ _ROT
    ;[lpBuf, lpKey, dwBufLen, dwKeyLen, A, B, pS]
    @ _ROT
    ;[lpBuf, lpKey, dwBufLen, dwKeyLen, B, pS, A]
    @ _OVER
    @ _OVER
    @ _ADD
    ;[lpBuf, lpKey, dwBufLen, dwKeyLen, B, pS, A, pS+A]
    @ _LOADCB, 0x2
    @ _PICK
    ;[lpBuf, lpKey, dwBufLen, dwKeyLen, B, pS, A, pS+A, pS]
    @ _LOADCB, 0x4
    @ _PICK
    @ _ADD
    ;[lpBuf, lpKey, dwBufLen, dwKeyLen, B, pS, A, pS+A, pS+B]
    @ _OVER
    @ _FETCHB
    @ _OVER
    @ _FETCHB
    @ _SWAP
    @ _ROT
    @ _STOREB
    @ _SWAP
    @ _STOREB
    @ _LOADCB, 0x1
    @ _ADD
    @ _LOADCD, .for2_up-.tofor2_up
    .tofor2_up:
    @ _JMPR
    .for2_down:
    ;[lpBuf, lpKey, dwBufLen, dwKeyLen, B, pS, A]
    @ _ROT
    ;[lpBuf, lpKey, dwBufLen, dwKeyLen, pS, A, B]
    @ _LOADCB, 0x3
    @ _ROLL
    @ _DROP
    ;[lpBuf, lpKey, dwBufLen, pS, A, B]
    @ _LOADCB, 0x4
    @ _ROLL
    @ _DROP
    @ _SWAP
    ;[lpBuf, dwBufLen, pS, B, A]
    .for3_up:
    @ _LOADCB, 0x3
    @ _ROLL
    @ _DUP
    ;[lpBuf, pS, B, A, dwBufLen, dwBufLen]
    @ _LOADCD, .for3_down-.tofor3_down
    .tofor3_down:
    @ _JMPC
    @ _LOADCB, 0x1
    @ _SUB
    ;[lpBuf, pS, B, A, dwBufLen]
    @ _SWAP
    @ _LOADCB, 0x1
    @ _ADD
    @ _LOADCB, 0xFF
    @ _AND
    ;[lpBuf, pS, A, dwBufLen, (A+1)%255]
    @ _ROT
    ;[lpBuf, pS, dwBufLen, (A+1)%255, B]
    @ _OVER
    @ _LOADCB, 0x4
    @ _PICK
    @ _ADD
    @ _FETCHB
    @ _ADD
    @ _LOADCB, 0xFF
    @ _AND
    @ _OVER
    @ _OVER
    @ _LOADCB, 0x5
    @ _PICK
    @ _ADD
    @ _SWAP
    @ _LOADCB, 0x5
    @ _PICK
    @ _ADD
    @ _OVER
    @ _OVER
    ;
    @ _OVER
    @ _FETCHB
    @ _OVER
    @ _FETCHB
    @ _SWAP
    @ _ROT
    @ _STOREB
    @ _SWAP
    @ _STOREB
    ;
    @ _FETCHB
    @ _SWAP
    @ _FETCHB
    @ _ADD
    @ _LOADCB, 0xFF
    @ _AND
    @ _LOADCB, 0x4
    @ _PICK
    @ _ADD
    @ _FETCHB
    @ _LOADCB, 0x5
    @ _PICK
    @ _FETCHB
    @ _XOR
    @ _LOADCB, 0x5
    @ _PICK
    @ _STOREB
    @ _LOADCB, 0x4
    @ _ROLL
    @ _LOADCB, 0x1
    @ _ADD
    @ _ROT
    @ _ROT
    @ _LOADCB, 0x4
    @ _ROLL
    @ _LOADCB, 0x4
    @ _ROLL
    @ _LOADCB, 0x3
    @ _ROLL
    @ _LOADCB, 0x3
    @ _ROLL
    @ _LOADCB, 0x3
    @ _ROLL
    @ _ROT
    @ _ROT
    @ _SWAP
    @ _LOADCD, .for3_up-.tofor3_up
    .tofor3_up:
    @ _JMPR
    .for3_down:
    @ _DROP
    @ _DROP
    @ _DROP
    @ _DROP
    @ _DROP
    @ _RET
« Last Edit: December 13, 2014, 08:46:32 pm by 0xDADA11c7 »