I'll dig around for it. I know I still have the assembler. But keep in mind that it is much more an obfuscated program than a 'vm'. Here is a program that demonstrates the basic principle.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
|
#include <cassert>
#include <cstdlib>
#include <iostream>
class Cpu {
public:
virtual int dummy( int, int ) {}
private:
virtual int add_( int a, int b ) { return a + b; } /* A */
virtual int sub_( int a, int b ) { return a - b; } /* B */
virtual int mul_( int a, int b ) { return a * b; } /* C */
virtual int div_( int a, int b ) { return a / b; } /* D */
virtual int mod_( int a, int b ) { return a % b; } /* E */
virtual int and_( int a, int b ) { return a & b; } /* F */
virtual int or_( int a, int b ) { return a | b; } /* G */
virtual int xor_( int a, int b ) { return a ^ b; } /* H */
};
int main( int argc, char* argv[] ) {
typedef int (Cpu::*Memfun)( int, int );
union {
Memfun fn;
unsigned char ptr[6];
} u;
Cpu cpu;
u.fn = &Cpu::dummy;
assert( argc == 4 );
int p1 = atoi( argv[ 1 ] );
int p2 = atoi( argv[ 3 ] );
char op = argv[2][0];
assert( op >= 'A' && op <= 'H' );
u.ptr[0] = 1 + 4 * ( op - 'A' + 1 ); // Don't look here!
std::cout << "The answer is " << ( (cpu.*(u.fn))( p1, p2 ) ) << std::endl;
}
|
NOTE: this program may not work on any compiler other than gcc, and even then I won't guarantee it will work with all versions of gcc. It exploits an internal detail of how gcc implements pointers to virtual member functions. [A note of interest is that the pointer to member function is actually 6 bytes long, not 4.]
g++ --version
g++ (GCC) 3.3.3 20040412 (Red Hat Linux 3.3.3-7)
Copyright (C) 2003 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Compile with
g++ main.cpp -o cpu
To run,
cpu <number> <letter> <number>
where each <number> is an integer, and <letter> is one of A, B, C, D, E, F, G, or H.
Each letter defines a mathematical operation as commented.
Note that nowhere does the program source actually reference any member function
except dummy, which is an empty function, yet all of the member functions are called.
(Note that the member functions are even private, but still called :)
EDIT: also, a little endian architecture is required to run properly.