Turns out that the Wikipedia entry on "self-modifying code" has a great list:
- Semi-automatic optimization of a state dependent loop.
- Runtime code generation, or specialization of an algorithm in
runtime or loadtime (which is popular,
for example, in the domain of
real-time graphics) such as a general
sort utility preparing code to perform
the key comparison described in a
specific invocation.
- Altering of inlined state of an object, or simulating the high-level
construction of closures.
- Patching of subroutine address calling, as done usually at load time
of dynamic libraries, or, on each
invocation patching the subroutine's
internal references to its parameters
so as to use their actual addresses.
Whether this is regarded as
'self-modifying code' or not is a case
of terminology.
- Evolutionary computing systems such as genetic programming.
- Hiding of code to prevent reverse engineering, as through use of a
disassembler or debugger.
- Hiding of code to evade detection by virus/spyware scanning software and
the like.
- Filling 100% of memory (in some architectures) with a rolling pattern
of repeating opcodes, to erase all
programs and data, or to burn-in
hardware.
- Compression of code to be decompressed and executed at runtime,
e.g., when memory or disk space is
limited.
- Some very limited instruction sets leave no option but to use
self-modifying code to achieve certain
functionality. For example, a "One
Instruction Set Computer" machine that
uses only the
subtract-and-branch-if-negative
"instruction" cannot do an indirect
copy (something like the equivalent of
"*a = **b" in the C programming
language) without using self-modifying
code.
- Altering instructions for fault-tolerance
On the point about thwarting hackers using self-modifying code:
Over the course of several firmware updates, DirectTV slowly assembled a program on their smart card to destroy cards that have been hacked to illegally receive unpaid channels. See Jeff's Coding Horror article on the Black Sunday Hack for more information.