🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.arch
Article #2507

Re: Self-modifying code

#2507
From: Robert Firth
Date: Tue, 10 Oct 1989 19:17
63 lines
3218 bytes
In article <1080@mipos3.intel.com> jpoon@mipos2.intel.com (Jack Poon~) writes:

>Could any experts out there educate me WHY and HOW does self-modifying code use?
>What the advantage of using self-modifying code that non-self-modifying code
>cannot achieve?

In the spirit of this question, I won't discuss why the current consensus
is that self-modifying code is bad, but rather will give examples.

Directly self-modifying code is pretty rare nowadays, but used to be
an essential tool.  Consider how you access an array element, A[i],
on a modern machine:

	Load index-register, i
	Load accumulator, address-of-A[0](index-register)

Some older machines didn't have index registers, so your compiler
generated this:

	Load accumulator, i
	Add accumulator, address-of-A[0]
	Store accumulator, right-half-of-instruction-L
L:	Load accumulator, contents-of-address-0

So, by the time you executed L, the right operand had been modified to
read 'contents-of-address-A[i]'.  And, basically, you HAD to do it this
way.

Some debuggers still play this trick.  If you set a breakpoint at L,
the debugger actually overwrites instruction L with 'trap-to-debugger',
of course saving the old instruction for subsequent execution.

----

Rather more common, are systems where code is generated and executed
dynamically.  Of course, any code overlay system is like that: a data
area is allocated, filled with bits read from a file, and then jumped
into and obeyed as code.  A more sophisticated system allows the
dynamic replacement of code bodies by alternative versions; thus, if
during debugging you suspect the new version of "munge()" is bad, you
replace it with the old version, read in from some file in the program
development environment, and carry on running.

This doesn't need true self-modifying code; rather, it needs dynamic
variability of procedure bodies (eg called via pointers), and the
ability to remap pieces of memory from data space into code space.

----

Finally, one very powerful technique is used in some implementations
of prototyping languages.  Typically, such languages are interpreted,
so each statement in 'Object Logo Plus', or whatever, is turned into
a data structure that is crawled over by an interpreter.

The trick is this: keep track of how often a code fragment (procedure,
method, or whatever) is modified, and how often it is executed.  When
a certain stability threshold is reached, compile the sucker into true
machine code, and have all subsequent executions be direct rather than
interpreted.  Over a prototyping session of an hour or two, the user
will observe a speedup of 2x to 20x, as the more stable and heavily used
parts of the program get converted gradually into machine code.

Hope that helps.
Technical Details
Message-ID: <4415@bd.sei.cmu.edu>
Path: arc1-ca.pugleaf.net!utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!tut.cis.ohio-state.edu!pt.cs.cmu.edu!sei!firth
References: <1080@mipos3.intel.com>

Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!tut.cis.ohio-state.edu!pt.cs.cmu.edu!sei!firth
From: firth@sei.cmu.edu (Robert Firth)
Newsgroups: comp.arch
Subject: Re: Self-modifying code
Message-ID: <4415@bd.sei.cmu.edu>
Date: 10 Oct 89 19:17:14 GMT
References: <1080@mipos3.intel.com>
Reply-To: firth@sei.cmu.edu (Robert Firth)
Organization: Software Engineering Institute, Pittsburgh, PA
Lines: 63