R0 CREW

[FASM x86] Миниатюрня софтверная стековая виртуальная машина

Эта ВМ использовалась в пакере, поэтому она имеет некоторые особенности. Должен заметить, что когда я говорю про виртуальную машину, то имею в виду семью подобных виртуальных машин, потому что для каждой потребности генерируеться своя виртуальная машина. Приведенная ниже ВМ официально утверждена “иридиевым” образцом в вакууме для использования в примерах.

Описание архитектуры виртуальной машины

  • Два 32-розрядных стека - данных и возвратов.
  • Собственное адресное пространство отсуствует, тоесть используется адресное пространство “хоста” (в данном случае x86 IA-32).
  • Формат хранение целых чисел интеливский (little-endian)
  • Доступ к памяти возможен байтами (Byte), словами (2 байти - Word) и двойными словами (4 байта - DWord)
  • размер колибается в границах 700-750 байт
  • номера функций, опкоды команд и расположение полей в структуре каждой ВМ свои
  • выполнено в виде шеллкода

Исходный код виртуальной машины
Файл заголовков picovm.inc

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.asm

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

Характеристики виртуальной машины сохраняються в JSON формате в файле picovm.settings.json

{"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"]}

Примеры использования

Для сокращения исходного кода я использую следующий макрос

macro @ cmd, p {
 PICOVM_CMD cmd, p
}

Функция роскодирования BASE85 с пользовательским алфавитом:

; BASE85
;[pAlphabet, pSrc, pDst, Size]
BASE85:
@ _DUP
@ _LOADCW, 0x0
@ _EQ
@ _NOT
@ _LOADCD, .Down-.toDown
.toDown:
@ _JMPC
@ _LOADCB, 0x5
@ _SUB
@ _ROT
;[pAlphabet, pDst, Size, pSrc]
@ _LOADCW, 0x3
@ _PICK
;[pAlphabet, pDst, Size, pSrc, pAlphabet]
@ _SWAP
;[pAlphabet, pDst, Size, pAlphabet, pSrc]
@ _LOADCD, DECODE_DWORD-.toDecodeDWord
.toDecodeDWord:
@ _CALLR
;[pAlphabet, pDst, Size, pSrc, DW]
@ _LOADCW, 0x3
@ _PICK
;[pAlphabet, pDst, Size, pSrc, DW, pDst]
@ _STORED
;[pAlphabet, pDst, Size, pSrc]
@ _ROT
;[pAlphabet, Size, pSrc, pDst]
@ _LOADCD, 0x4
@ _ADD
@ _ROT
;[pAlphabet, pSrc, pDst, Size]
@ _LOADCD, BASE85-.toUp
.toUp:
@ _JMPR
.Down:
@ _DROP
@ _DROP
@ _DROP
@ _DROP
@ _RET

;[pAlphabet, pSrc] => [pSrc, DW]
DECODE_DWORD:
@ _LOADCB, 0
@ _OVER
@ _FETCHB
;[pAlphabet, pSrc, 0, [pSrc]]
@ _LOADCW, 0x3
@ _PICK
@ _SWAP
;[pAlphabet, pSrc, 0, Alphabet, [pSrc]]
@ _LOADCD, SEARCHB -.toSearchB1
.toSearchB1:
@ _CALLR
@ _ADD
@ _SWAP
@ _LOADCW, 0x1
@ _ADD
@ _SWAP
@ _OVER
@ _FETCHB
@ _LOADCD, 0x3
@ _PICK
@ _SWAP
@ _LOADCD, SEARCHB -.toSearchB2
.toSearchB2:
@ _CALLR
@ _LOADCB, 0x55
@ _MUL
@ _ADD
@ _SWAP
@ _LOADCB, 0x1
@ _ADD
@ _SWAP
@ _OVER
@ _FETCHB
@ _LOADCD, 0x3
@ _PICK
@ _SWAP
@ _LOADCD, SEARCHB -.toSearchB3
.toSearchB3:
@ _CALLR
@ _LOADCW, 85*85
@ _MUL
@ _ADD
@ _SWAP
@ _LOADCB, 0x1
@ _ADD
@ _SWAP
@ _OVER
@ _FETCHB
@ _LOADCD, 0x3
@ _PICK
@ _SWAP
@ _LOADCD, SEARCHB -.toSearchB4
.toSearchB4:
@ _CALLR
@ _LOADCD, 85*85*85
@ _MUL
@ _ADD
@ _SWAP
@ _LOADCW, 0x1
@ _ADD
@ _SWAP
@ _OVER
@ _FETCHB
@ _LOADCW, 0x3
@ _PICK
@ _SWAP
@ _LOADCD, SEARCHB -.toSearchB5
.toSearchB5:
@ _CALLR
@ _LOADCD, 85*85*85*85
@ _MUL
@ _ADD
@ _ROT
@ _DROP
@ _SWAP
@ _LOADCD, 0x1
@ _ADD
@ _SWAP
@ _RET

SEARCHB:
@ _OVER
@ _SWAP
.Up:
@ _OVER
@ _FETCHB
@ _OVER
;[pMem, pMem, bVal, [pMem], bVal]
@ _EQ
;[pMem, pMem, bVal, BOOL]
@ _NOT
@ _LOADCD, .Down-.toDown
.toDown:
@ _JMPC
@ _SWAP
@ _LOADCB, 0x1
@ _ADD
@ _SWAP
@ _LOADCD, .Up-.toUp
.toUp:
@ _JMPR
.Down:
@ _DROP
@ _SWAP
@ _SUB
@ _RET

Криптографическая функция RC4

; [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

Как сказано выше, каждая виртуальная машина создаеться генератором і являеться уникальной.

Исходный код генератора виртуальных машин на JavaScript
picovm.js

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);

Изначально написано для украинского форума программистов

Спасибо ценная наработка, думаю пригодится в хозяйстве

Напомнило мне стек-ориентированную машину из игрового движка Q3, тогда небыло всяких дот нетов и ребята того времени видимо писали свои велосипеды не напрягаясь, получилось чесно сказать не плохо. Шас изленившиеся прикладники в геймдеве такое не повторят, да и незачем. Из заметных приемуществ: код VM пишется на кошерном C, из недостатков: само двигло VM тоже написано на C, недостаток это или нет уже зависит от области применения

Я на движок Q3 тоже поглядывал, но отбросил всё “лишнее”, чтоб аверам больше работы досталось.

ScummVM вам у помощь, хотя это только портирование движков на новые платформы, но пишут то вполне современные прикладники в геймдеве. Та ж Сиерра в своих древних играх ВМ использует куда экзотичнее по архитектуре Q3.

Не, я о том что раньше портируемость давалась с боем, сейчас так никто не делает, готовых решений полно. По поводу VM сиерры, сорсы где-то есть?

Сорцов нет (не считая ScummVM), но есть спецификация ВМ. Я очень давно видел подробно документированный дизасм в формате, кажаться в виде сообщений ФИДО :slight_smile:

подниму тему,
0xDADA11C7
вы автор ? можете описать принцип работы стэковой виртуалки?