Related articles |
---|
Self-modifying code, Function pointers & { Safety, Security} seimarao@gmail.com (Seima Rao) (2014-03-07) |
Re: Self-modifying code, Function pointers & { Safety, Security} kaz@kylheku.com (Kaz Kylheku) (2014-03-09) |
Re: Self-modifying code, Function pointers & { Safety, Security} martin@gkc.org.uk (Martin Ward) (2014-03-14) |
Re: Self-modifying code, Function pointers & { Safety, Security} tenger@iseries-guru.com (Terrence Enger) (2014-03-15) |
Re: Self-modifying code, Function pointers & { Safety, Security} seimarao@gmail.com (2014-03-20) |
Re: Self-modifying code, Function pointers & { Safety, Security} federation2005@netzero.com (2014-04-13) |
Re: Self-modifying code, Function pointers & { Safety, Security} monnier@iro.umontreal.ca (Stefan Monnier) (2014-04-16) |
From: | Martin Ward <martin@gkc.org.uk> |
Newsgroups: | comp.compilers |
Date: | Fri, 14 Mar 2014 14:15:13 +0000 |
Organization: | Compilers Central |
References: | 14-03-015 |
Keywords: | code, comment |
Posted-Date: | 14 Mar 2014 13:47:06 EDT |
On 07/03/14 16:04, John wrote:
> [The major reasons for self-modifying code historically were for
> address modification for indexing and subroutine returns. Index
> registers and indirect addressing provide instruction modification as
> the instruction is executed, making those modifications go away.... -John]
The IBM mainframe instruction set includes an "Execute" instruction
(EX) which takes a register and an address. The instruction at the
given address is loaded into memory, part of it is overwritten by the
low byte from the register, and the resulting modified instruction is
executed.
The most common use for Execute is to modify the length field of an
instruction to give a variable length move or compare.
As common with many IBM instructions, the Execute instruction includes
an index register field: so an instruction can be selected for
execution from a table of instructions, depending on the value in the
given index register.
Despite the presence of Execute, and the fact that more recent
mainframes now include variable length move and comare instructions,
self modifying code is still quite common in assembler code which is
currently in production.
One of the most common cases is overwriting a NOP (branch never)
instruction to convert it into a B (unconditional branch) instruction.
This is typically used to set up a "first time through" switch, for
example:
NOPINSTR NOP LAB1
MVI NOPINSTR+1,X'F0'
initialisation code...
LAB1 ...
The first time through, the NOP instruction does not branch, so
control falls through to the MVI instruction (move immediate) which
overwrites part of the NOP instruction, turning it into an
unconditional branch. Subsequent executions will then skip the
initialisation code. The advantage of this approach (over setting and
testing a flag) is that it saves five whole bytes of memory: one byte
for the flag and four more bytes for the compare instruction. It also
saves executing one instruction.
The other common cases for self-modifying code are modifying the
length field (directly in the instruction, rather than indirectly via
an Execute instruction), modifying one or more displacement fields
(i.e. modifying the address of the data that the instruction operates
on) and modifying the data field of an immediate data instruction.
I recently carried out a survey of several million lines of current
production assembler in three organisations. Self-modifying code
appeared in all code bases, with the amounts varying considerably
between organisations. The numbers below are per million lines of
executable instructions:
Organisation A:
24 EXecute instructions
2,685 modified branch instructions
3,451 modified length fields
490 modified immediate data fields
1,578 modified displacements
Organisation B:
722 EXecute instructions
1,236 modified branch instructions
626 modified length fields
74 modified immediate data fields
429 modified displacements
Organisation C:
1,222 EXecute instructions
76 modified branch instructions
107 modified length fields
0 modified immediate data fields
90 modified displacements
Any automated assembler analysis or migration tool therefore needs to
be able to detect and handle all these cases of self-modifying code
(as ours does, of course!)
As well as saving memory space, self-modifying code was used to
improve exection speed. Ironically, on modern mainframes,
self-modifying code will dirty the instruction cache: forcing the CPU
to re-load from main memory and killing performance!
I can only think of two cases (out of all the production assembler code
we have ever processed) in which a block of instructions is written
to memory and subsequently executed.
--
Martin
Dr Martin Ward STRL Principal Lecturer & Reader in Software Engineering
martin@gkc.org.uk http://www.cse.dmu.ac.uk/~mward/ Erdos number: 4
G.K.Chesterton web site: http://www.cse.dmu.ac.uk/~mward/gkc/
Mirrors: http://www.gkc.org.uk and http://www.gkc.org.uk/gkc
[Thanks, this is quite interesting. Mainframe sort programs compile
the sort instructions into machine code that does the record editing
and comparison, but they write the code out as an object file on disk,
and then use the link editor or loader to combine it with any user
exit routines and bring it into memory, where the main sort program
can call it. Given the large size of most sort jobs, the extra time for
the linkedit is insignficant. -John]
Return to the
comp.compilers page.
Search the
comp.compilers archives again.