From: jinx@zurich.ai.mit.edu (Guillermo J. Rozas)
Newsgroups: comp.sys.intel
Subject: Re: 386 <-> 486 incompatibilities
Date: 13 Aug 92 17:10:53 GMT
Reply-To: jinx@zurich.ai.mit.edu
Organization: M.I.T. Artificial Intelligence Lab.
In-reply-to: eggenste@cantor.informatik.uni-dortmund.de's message of 13 Aug 92 14:37:24 GMT

In article <16ds34INNpvn@fbi-news.Informatik.Uni-Dortmund.DE> eggenste@cantor.informatik.uni-dortmund.de (Heinz-Bernd Eggenstein) writes:

|   From: eggenste@cantor.informatik.uni-dortmund.de (Heinz-Bernd Eggenstein)
|   Newsgroups: comp.sys.intel
|   Date: 13 Aug 92 14:37:24 GMT
|
|   Hello!
|
|   Among the few MS-DOS programs that will run on a 80386, but not on
|   an i486 based machine, there's a program called "PC Scheme"
|   by Texas Instruments (Scheme is a Lisp-like language). 
|
|   According to rumors, this is a result of the program changing 
|   some instructions in its own code-segment at runtime. 
|
|   -How can this cause incompatibilities between 
|    80386 and i486 processors?
|   -I don't think every  self-modification of a program will
|    cause problems. Exactly under what conditions may 
|    problems occur? 
|   -Is there a way to detect this kind of self-modification
|    either at runtime (say, with a small TSR debugger-like program) or 
|    scanning the assembly-code sources.
|   -Are there any other mayor causes for i486 incompatibilities?
|

The 486 does not have split I and D caches, so the only way this sort
of practice can lose is if the instruction being modified is in the
same pre-fetch block as the instruction doing the modification.

The i486 Microprocessor Programmer's Reference Manual states in
section 12.2.3:

"12.2.3:

Self-modifying Code

A write to an instruction in the cache will modify it in both the
cache and memory, but if the instruction was prefetched before the
write, the old version of the instruction could be the one executed.
To prevent this, flush the instruction prefetch unit by coding a jump
instruction immediately after any write that modifies an instruction."

Of course, this has nothing to do with self-modifying code becase it
applies equally well to newly generated code.

In general you can't detect such modification unless you emulate the
code.  If you are replacing an old instruction, the old one will be
executed, and there may be nothing wrong with it that the processor
will detect.

However, if the instructions are always written into previously unused
memory (and therefore it is not true self-modification), you could
pre-initialize such memory with debugging instructions (e.g. `INT 3' =
#xCC in Scheme = 0xcc in C).

You would have to add an interrupt handler for INT 3 which could check
the contents of the address where the interrupt occurred.  If it was
still `INT 3', you would continue into the normal handler.  If it was
not, it would mean that it was a spurious prefetch problem, and merely
backing up the PC (if necessary, I don't remember which of the PCs
would be reported in the interrupt structure) and continuing normally
would fix the problem, since the prefetch buffer would have been
flushed by the interrupt.  Even more cleverly, if the alignment of the
new instructions is fixed and sufficient, you could pre-initialize
your memory with instructions to CALL an out-of-line handler at a
fixed address.  This out-of-line handler would back up the PC and jump
right back, since the prefetch buffer would already be clear.

There are other differences with the i386 processor.  The most
noticeable are various new instructions and mode bits, especially the
"Alignment Check" bit.  If the "Alignment Check" bit is turned on
(which I doubt because many PC programs would lose, not only PC
Scheme), reading and writing to memory (MOV instructions) is legal
only at addresses which are integer multiples of the size of the
transfer (e.g. even addresses for 16-bit moves, addresses divisible by
4 for 32-bit moves).

I hope this helps.
Xref: sparky comp.sys.intel:1563 comp.sys.palmtops:2736