The semantics are the hard part. Just making a bytecode for some language isn't hard. The problem is coming up with some semantics that allow all languages to be implemented efficiently on top of it. Turns out that's extremely difficult. The JVM and .NET certainly didn't achieve that; the Java-fied and .NET-ified versions of languages are typically slower and don't integrate well with their host languages.