[comp.sys.amiga.tech] Self Modifying Code!

brett@smosjc.UUCP (Brett Coon) (07/06/90)

Is there an acceptable means to write self-modifying code on the Amiga?

Assuming for the sake of argument that I have a good reason to do such
a thing (and there's a good chance I don't), can I do it without risking
future compatibility?  My current plan is to select one of a few possible
versions of the code at the beginning, and then patch the code to use the
appropriate version.  It would be done once, during initialization, so 
performance at this point is entirely unimportant.  What I envision is an
operating system call to clear the instruction cache, or do nothing if there
is no cache.  Surely something like this is done by the loader, right?

Please, don't tell me the evils of self-modifying code, I'll only use it if
I have to.  Pretend this question is entirely academic.

-brett
-- 
|Brett Coon           |  uunet!smosjc!brett         |
|S-MOS Systems, Inc.  |  "You like 'em, anchovies?" |
|San Jose, CA         |            -Runaway Train   |

ckp@grebyn.com (Checkpoint Technologies) (07/06/90)

In article <293@smosjc.UUCP> brett@smosjc.UUCP (Brett Coon) writes:
>Is there an acceptable means to write self-modifying code on the Amiga?
>
>Assuming for the sake of argument that I have a good reason to do such
>a thing (and there's a good chance I don't), can I do it without risking
>future compatibility?  My current plan is to select one of a few possible
>versions of the code at the beginning, and then patch the code to use the
>appropriate version.  It would be done once, during initialization, so 
>performance at this point is entirely unimportant.  What I envision is an
>operating system call to clear the instruction cache, or do nothing if there
>is no cache.  Surely something like this is done by the loader, right?
>
>Please, don't tell me the evils of self-modifying code, I'll only use it if
>I have to.  Pretend this question is entirely academic.

OK, well, there's a purely theoretical way to do it that is free of
danger from any kind of cache problems...

Write your code out to a file in hunk format, then LoadSeg() it in.  For
better speed, write it to RAM:, that should work just as well.
LoadSeg() must be capable of dealing with stale instruction cache in the
presence of any large cache, or it won't work.  On the 68030, I don't
think it does, but then, after all the writing and reading, it's truly
doubtful that there'd be any stale I-cache in the area of your new
segment.

Oh, and BTW, this will work under 1.3.  The other suggestion, use the
new 2.0 cache control function, will only work under 2.0 and later.

And finally, of course... self-modifying code is not a good thing to
do.
-- 
First comes the logo: C H E C K P O I N T  T E C H N O L O G I E S      / /  
                                                                    \\ / /    
Then, the disclaimer:  All expressed opinions are, indeed, opinions. \  / o
Now for the witty part:    I'm pink, therefore, I'm spam!             \/

forgeas@swinjm.UUCP (Jean-Michel Forgeas) (07/07/90)

In article <293@smosjc.UUCP> brett@smosjc.UUCP (Brett Coon) writes:
>Is there an acceptable means to write self-modifying code on the Amiga?
>
>[...]  My current plan is to select one of a few possible
>versions of the code at the beginning, and then patch the code to use the
>appropriate version.

You have at least one other solution: use vectors.

struct FuncNeeded {
    void (*func1)();
    void (*func2)();
    };
struct FuncNeeded Version1 = { Func1_1, Func1_2 };
struct FuncNeeded Version2 = { Func2_1, Func2_2 };
struct FuncNeeded *Version;

init()
{
    Version = (TheVersionYouWant ? &Version1 : &Version2 )
}

program()
{
    ...
    (*(Version->func1))();
    ...
    retcode = (int*) (*(Version->func2))();
    ...
}

> It would be done once, during initialization, so
>performance at this point is entirely unimportant.

It could be coded in asm like:

init:
    ...
    lea     Version1,a5     use a base register
    rts

program:
    ...
    move.l  func2vectoroffset(a5),a0
    jsr     (a0)
    ...
    rts

--
                                            \___/
Jean-Michel Forgeas                          \-/
cbmvax!cbmbsw!cbmsup!cbmfra!swinjm!forgeas    |    The Software Winery
                                             -^-
                                 And, where is the universe ?

daveh@cbmvax.commodore.com (Dave Haynie) (07/07/90)

In article <293@smosjc.UUCP> brett@smosjc.UUCP (Brett Coon) writes:
>Is there an acceptable means to write self-modifying code on the Amiga?

Overall, no.  However, a side effect of using a 68000 CPU is that most,
but not necessarily all, self-modifying code tricks work.  So, if you 
test ExecBase->AttnFlags for 68000, and avoid the self modifying code
if you find you're not running on the 68000.

>Assuming for the sake of argument that I have a good reason to do such
>a thing (and there's a good chance I don't), can I do it without risking
>future compatibility?  

Well, as you said, there's a good chance that you don't.  An extremely good
chance.  Because self-modifying code is never necessary.  Sometimes it'll 
allow a very specific thing to be done faster.  In the general case, it's 
foolish to risk limiting your product's market to old Amigas just to make
things go slightly faster.  Providing redundant routines for the same operation
is probably the best thing you can do.  As long as Motorola doesn't change the
68000 (which they certainly could, since they don't support self-modifying 
code either, but probably won't, since they have better things to do), you're
OK if you run correct code when you find a 68020 or better in charge.

>What I envision is an operating system call to clear the instruction cache, 
>or do nothing if there is no cache.  Surely something like this is done by 
>the loader, right?

Well, there is an OS call to clear the caches in 2.0, but that's still 
something you shouldn't use execept when necessary.  And you should realize
just what self-modifying code actually is.  If you're choosing one of 
several subroutines, you most likely aren't self-modifying.  Assignment of
function pointers is done by hand in C all the time, and C++ actually 
formalizes a similar mechanism via its virtual function mechanism.  The 
problem of self-modifying code occurs, from an application's point of view,
when the application runs through a code chunk, modifys that code chunk, and
then runs through it once again.

>Please, don't tell me the evils of self-modifying code, I'll only use it if
>I have to.  Pretend this question is entirely academic.

My advice is to never use self modifying code, but also to make sure you 
really know what constitutes self modifying code.  
-- 
Dave Haynie Commodore-Amiga (Amiga 3000) "The Crew That Never Rests"
   {uunet|pyramid|rutgers}!cbmvax!daveh      PLINK: hazy     BIX: hazy
	"I have been given the freedom to do as I see fit" -REM

vilkas@ultima.cs.uts.oz (Jhary a Conel) (07/09/90)

brett@smosjc.UUCP (Brett Coon) writes:

>Is there an acceptable means to write self-modifying code on the Amiga?

>Assuming for the sake of argument that I have a good reason to do such
>a thing (and there's a good chance I don't), can I do it without risking
>future compatibility?  My current plan is to select one of a few possible
>versions of the code at the beginning, and then patch the code to use the
>appropriate version.  It would be done once, during initialization, so 

>-brett


	Maybe I am off the track on this, but have you thought about using
the DOS loadseg() command. I am not sure how to use it (never have myself)
but if you have the different versions of the code in seperate code segments
then you could select which one you want and then use loadseg() to bring it 
into memory and there would be no need for any self modifying anything.

Just a suggestion.

Jhary

jesup@cbmvax.commodore.com (Randell Jesup) (07/10/90)

In article <293@smosjc.UUCP> brett@smosjc.UUCP (Brett Coon) writes:
>Is there an acceptable means to write self-modifying code on the Amiga?
>
>Assuming for the sake of argument that I have a good reason to do such
>a thing (and there's a good chance I don't), can I do it without risking
>future compatibility?  My current plan is to select one of a few possible
>versions of the code at the beginning, and then patch the code to use the
>appropriate version.  It would be done once, during initialization, so 
>performance at this point is entirely unimportant.  What I envision is an
>operating system call to clear the instruction cache, or do nothing if there
>is no cache.  Surely something like this is done by the loader, right?

	Well, if you _must_....

	First, check the cpu type.  If on an '030 or greater, check the OS
version.  If less than 36, use an '030 cache clear instruction.  If greater
or equal to 36, use CacheClearU (or CacheClearS from supervisor mode).  Check
the Autodocs on how to use it.

	Using CacheClearU/S means that if you are running on a post-030
processor or with external cache, the right things will happen.

	Under 2.0, LoadSeg uses this after patching relocation information,
as does the scsi disk driver after doing dma.

-- 
Randell Jesup, Keeper of AmigaDos, Commodore Engineering.
{uunet|rutgers}!cbmvax!jesup, jesup@cbmvax.cbm.commodore.com  BIX: rjesup  
Common phrase heard at Amiga Devcon '89: "It's in there!"

FelineGrace@cup.portal.com (Dana B Bourgeois) (07/12/90)

If the latest microprocessors don't allow self-modifying code does that
spell the end of core-wars type games on modern computers?  I guess I
could keep that C64 around for corewars you betcha!

Dana Bourgeois @ cup.portal.com

phorgan@cup.portal.com (Patrick John Horgan) (07/13/90)

Dana Bourgeois @ cup.portal.com said:
|If the latest microprocessors don't allow self-modifying code does that
|spell the end of core-wars type games on modern computers?  I guess I
|could keep that C64 around for corewars you betcha!
Nope, Dana, we just simulate with CRobots:)

Patrick