Yes, you can change any code. Of course in ROM you will have to generate a new one, since it does not allow writing.
You can decompile virtually any code, but some are quite difficult. You need to have lots of information that is not always available. In general reverse engineering is done on top of the same assembly, which is possible to get easy in 100% of situations.
Of course, no decompiled code will be as readable as the original.
Some languages use an information-rich, intermediate bytecode , so you can recreate the original code very closely. In general there will be small changes to the original form of the algorithm, but doing the same thing, the style will obviously be the decompiler, will not have comments, and will often lose local variable names.
Java, C # and any language that does not usually generate a native binary are like this. Note that C # can generate native code .
There's nothing you can do to stop it. What you can do is make it difficult, create situations that the decompiler gets complicated, that changes meaningful names to illegible things. But obfuscators can cause code execution problems .
Emulating a ROM has nothing to do with decompiling one.
There may be some confusion as to what a compiler is. There is a question that speaks of this: What is a programming language, IDE, and compiler? . And another one that talks how it works: How is a compiler done? .