Antes de tudo, vale a pena notar que a JVM da Sun foi escrita em C. C é uma linguagem muito popular quando é necessária portabilidade.
A linguagem C é portátil, embora muitos programas em C não sejam. Isso ocorre porque C não impõe tantas restrições ao programador nem faz tantas suposições. Se um programador de C quer que seus programas sejam portáteis, ele deve impor essas restrições.
Na prática, isso realmente não é muito mais difícil do que viver com as restrições que o Java força sobre você. É principalmente uma questão de estar atento aos seus tamanhos iniciais e primitivos, e usar bibliotecas portáteis como GTK + em vez de bibliotecas específicas da plataforma.
Você poderia criar um destino GTK + e um compilador C que suportasse uma máquina virtual, mesmo provavelmente a JVM, e fazer com que o código existente funcionasse com muito poucas alterações. De fato, sem a coleta de lixo, uma máquina virtual C provavelmente seria muito mais simples. Por que você iria querer?
O contrário, compilar Java para código nativo, é igualmente factível. Isso é basicamente o que o JIT faz. Por que você iria querer? Tenho certeza de que existem projetos de estimação para fazê-lo "apenas porque", mas eles não são muito usados.