OK I've taken your comments into account.
Now I think I finally got it right:
mov ecx, [ebx] ; ecx = code[pc]
inc ebx ; pc ++
jmp ecx ; goto code[pc], as ecx is already a pointer
Nope, ecx is an opcode, not a pointer. You need another
indirection.
Man this has been frustrating to read. I understood what Dmitry
was talking about over at least dozen posts ago, and that's
without actually reading the article about interpreters (I did
write a SNES emulator once, but it didn't use this cool
technique. I did, however, have to write it in assembly because
the C version was dog-slow because e.g. I couldn't capture the
overflow/negative/zero flags in C.)