I have a simple virtual machine which I made for fun. It works in a very low level and it doesn't have any notion of types. Everything is just an integer. There are some instructions for getting a pointer and accessing memory by a pointer. The problem is that these pointers are simply stored as uint64_t, and any pointer arithmetic is an integer arithmetic. The machine casts this to a void* when using it as a pointer. Well, this kind of code is obvious in the assembly level, but the C and C++ standard doesn't let programmers do integer-pointer cast safely, especially when the integer is used to change the value of the pointer.
I'm not making this toy VM portable everywhere. It is just expected to work under x86_32/64 machines, and it does seem to work very fine even after full compiler optimizations. I think it's because pointers are represented no differently as integers in the x86 architecture.
What kind of solution is usually applied in such situations, that the language standards doesn't declare certain code as safe, but it really should be safe in the targeted hardware, and the results does seem okay?
Or as a more practical question, how can I let a compiler (gcc) not perform breaking optimizations on code like
uint64_t registers[0x100];
registers[0] = (uint64_t)malloc(8);
registers[0] += 4;
registers[2] = 0;
memcpy(®isters[2], (void*)registers[0], 4);
The above isn't real code, but a certain sequence of bytecode instructions would actually do something similar as above.