Of course you can unwind self modifying code to some sort of semantic equivalent version. However, self modifying code where timing and external state or internal cache behavior is part of what influences the output CANNOT be represented except by anything beyond perhaps a good high level description language with a compiler or translator that can take that description back to its binary original.
If the output of a Turing machine is the entire state at each step, the sequence itself would be impossible to replicate even though this requires an alternative definition of a TM to capture these hidden practical states.
Furthermore forgetting these issues, the question of whether a given self modifying code can be unrolled in P time or P space is hardly proven. It could be that removing all self modifying code causes an exponential blow up in program size. It's also the case that optimal Kolnogorov complexity might only be achievable via self modifying code.
So the fact that it can theoretically be unrolled in all cases, says nothing about its impact on complexity, nor does it work in a practical environment which has micro instruction timing, cache issues, or even external clock type sensitivity which is measurable with modern processors very easily. It would be easy to make hand written assembly that detects if it is in it's original form verse a unwound form using several different techniques. Modern processors are highly complex state machines and effectively cannot be strictly modeled as TMs as there is no way to model an input tape that has external stimuli with such a primitive theoretical model. Immediately we must step into non deterministic or probabilistic TMs and NP or worse complexity