Primeiro, embora haja instruções que sejam muito semelhantes, não há um conjunto de instruções que sempre se comporte da mesma maneira em diferentes arquiteturas de CPU. Para emulação precisa, não é o suficiente (geralmente) para traduzir cada instrução - você tem que lidar com acessos de memória, temporizações, interrupções ... e isso é apenas para a CPU.
Parece que o que você está pensando é a recompilação estática, mas é muito difícil de fazer (na verdade, acho que se resume ao interrompendo o problema , tornando-o realmente impossível na teoria). Na prática, às vezes podemos fazer isso para um subconjunto de programas, mas você não pode escrever um compilador de propósito geral que usa o código de objeto para uma arquitetura como entrada e gera um código perfeitamente equivalente para outra. Por exemplo, seria difícil lidar com código auto-modificador usando esse método.
A recompilação dinâmica (que gera código on-the-fly enquanto o programa é executado) é mais bem sucedida (ainda não trivial para fazer o certo). Os problemas específicos dependerão da arquitetura, no entanto. Em muitos casos, emular a CPU não é o problema, mas emular vários dispositivos periféricos, mantendo o tempo exato, é (veja, por exemplo, artigo do byuu sobre como emular o SNES ).
Às vezes, você pode ignorar muitas dessas restrições e ainda simular hardware o suficiente para ter um subconjunto do software funcionando, mas nunca é possível (até onde eu sei) ter 100% de precisão com zero de sobrecarga, a menos que você tenha hardware real.