rbabel@babylon.rmt.sub.org (Ralph Babel) (03/09/91)
In article <18cb4d63.ARN0b56@swinjm.UUCP>, forgeas@swinjm.UUCP (Jean-Michel Forgeas) writes: > I don't see where you find self-modifying code in the > example above. All I see is data (while there is no > process running on it). Effectively after CreateProc() on ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ > it this data becomes code, but there is no modification of ^^^^^^^^^^^^^^^^^^^^^^^^^ > the code after CreateProc(). This is not true! It's always the function that brings the code into memory (e.g. LoadSeg()) that is supposed to keep the code cache up to date, not the function to execute this code (e.g. CreateProc()). The same code might be executed several times (even concurrently), so clearing the cache every time would be wasteful. These are the only legal ways of bringing code into memory: - ROM-code - DAC_WORDWIDE - DAC_BYTEWIDE - DAC_NIBBLEWIDE - MakeFunctions() - MakeLibrary() - SetFunction() - LoadSeg() Putting an entry into the Captures/KickTags and rebooting the system _might_ also be considered safe. 2.0 provides a few additional functions (e.g. InternalLoadSeg()) plus some cache control calls. In article <1991Mar9.170859.4810@Sandelman.OCUnix.On.Ca>, mcr@Sandelman.OCUnix.On.Ca (Michael Richardson) writes: > Please suggest an alternative to doing this. Simply use a function entry that is longword-aligned, e.g. an assembly language stub after a "CNOP 0,4" or the first (C-) function in an object module, and convert it to a seglist: void (*pfv)(void); BPTR sl; sl = (BPTR)(((ULONG)pfv >> 2) - 1); > So far code like this [PhonySegList] (Hmm. I don't have a > SegSize at the beginning though) has been working on > A3000s for some time now. 256 bytes of cache isn't a lot. It even works under 1.3. > Is there now a 2.0 function for doing the same thing? 2.0 dos.library allows one to specify a regular function address instead of a (longword-aligned) seglist. > /* From Leoproc.zoo. By Leo Schwab. */ > > CopyMem(&template, fakelist, sizeof(struct PhonySegList)); > fakelist->psl_EntryPoint = SlaveStart; Sorry, self-modifying code. Even if Leo did it. :-) Ralph
mcr@Sandelman.OCUnix.On.Ca (Michael Richardson) (03/10/91)
In article <06417.AA06417@babylon.rmt.sub.org> cbmvax.commodore.com!cbmehq!babylon!rbabel (Ralph Babel) writes: >In article <19578@cbmvax.commodore.com>, >ken@cbmvax.commodore.com (Ken Farinsky - CATS) writes: > >> LoadSeg() needs a BPTR to a seg list, which can be faked >> like: >> >> /* From Mike Sinz AmigaMail example */ >> struct CodeHdr >> { >> ULONG SegSize; /* sizeof(struct CodeHdr) */ >> ULONG NextSeg; /* Must be NULL */ >> UWORD JumpInstr; /* set to 0x4EF9 (a jump instruction) */ >> APTR Function; /* a pointer to the function */ >> } > >I'd call this self-modifying code. Please suggest an alternative to doing this. So far code like this (Hmm. I don't have a SegSize at the beginning though) has been working on A3000s for some time now. Is there now a 2.0 function for doing the same thing? /* From Leoproc.zoo. By Leo Shwab. */ struct PhonySegList { BPTR psl_NextSeg; /* BPTR to next element in list */ UWORD psl_JMP; /* A 68000 JMP abs.l instruction */ void (*psl_EntryPoint)(); /* The address of the function */ }; struct PhonySegList template = { NULL, /* No next element. */ 0x4EF9, /* JMP abs.l */ NULL /* Argument for JMP instruction */ }; ... /* * Allocate a PhonySegList structure. */ if((fakelist = AllocMem(sizeof(struct PhonySegList), NULL))==NULL || (startup = AllocMem(sizeof(struct SlaveStart),MEMF_PUBLIC))==NULL) { return(88); } /* * Copy the template into the allocated memory, and set the entry * point to the sub-process. */ CopyMem(&template, fakelist, sizeof(struct PhonySegList)); fakelist->psl_EntryPoint = SlaveStart; -- :!mcr!: | The postmaster never | - Pay attention only Michael Richardson | resolves twice. | to _MY_ opinions. - HOME: mcr@sandelman.ocunix.on.ca + Small Ottawa nodes contact me Bell: (613) 237-5629 + about joining ocunix.on.ca!
mcr@Sandelman.OCUnix.On.Ca (Michael Richardson) (03/11/91)
In article <06493.AA06493@babylon.rmt.sub.org> cbmvax.commodore.com!cbmehq!babylon!rbabel (Ralph Babel) writes: >In article <1991Mar9.170859.4810@Sandelman.OCUnix.On.Ca>, >mcr@Sandelman.OCUnix.On.Ca (Michael Richardson) writes: > >> Please suggest an alternative to doing this. > >Simply use a function entry that is longword-aligned, e.g. >an assembly language stub after a "CNOP 0,4" or the first >(C-) function in an object module, and convert it to a >seglist: > >void (*pfv)(void); >BPTR sl; > >sl = (BPTR)(((ULONG)pfv >> 2) - 1); Thank you. This had not occured to me, and I'm a little hesistant about it. We shall try this. >> CopyMem(&template, fakelist, sizeof(struct PhonySegList)); >> fakelist->psl_EntryPoint = SlaveStart; > >Sorry, self-modifying code. Even if Leo did it. :-) No dispute about it being not exactly kosher. I had assumed that the first long word (which was NULL, the next pointer) was used in some way. Probably we'll wind up assembling a short assembly program to 'jmp' to the right place rather than depend on the function being first. Actually, we are probably going to pull the two processes into seperate binaries. It will allow a lot more customization. (And a lot more user confusion :-) -- :!mcr!: | The postmaster never | - Pay attention only Michael Richardson | resolves twice. | to _MY_ opinions. - HOME: mcr@sandelman.ocunix.on.ca + Small Ottawa nodes contact me Bell: (613) 237-5629 + about joining ocunix.on.ca!
mcr@Sandelman.OCUnix.On.Ca (Michael Richardson) (03/11/91)
In article <06493.AA06493@babylon.rmt.sub.org> cbmvax.commodore.com!cbmehq!babylon!rbabel (Ralph Babel) writes: >In article <1991Mar9.170859.4810@Sandelman.OCUnix.On.Ca>, >mcr@Sandelman.OCUnix.On.Ca (Michael Richardson) writes: > >> Please suggest an alternative to doing this. > >Simply use a function entry that is longword-aligned, e.g. >an assembly language stub after a "CNOP 0,4" or the first >(C-) function in an object module, and convert it to a >seglist: > >void (*pfv)(void); >BPTR sl; > >sl = (BPTR)(((ULONG)pfv >> 2) - 1); Thank you. This had not occured to me, and I'm a little hesistant about it. We shall try this. >> CopyMem(&template, fakelist, sizeof(struct PhonySegList)); >> fakelist->psl_EntryPoint = SlaveStart; > >Sorry, self-modifying code. Even if Leo did it. :-) No dispute about it being not exactly kosher. I had assumed that the first long word (which was NULL, the next pointer) was used in some way. Probably we'll wind up assembling a short assembly program to 'jmp' to the right place rather than depend on the function being first. Actually, we are probably going to pull the two processes into seperate binaries. It will allow a lot more customization. (And a lot more user confusion :-) -- :!mcr!: | The postmaster never | - Pay attention only Michael Richardson | resolves twice. | to _MY_ opinions. - HOME: mcr@sandelman.ocunix.on.ca + Small Ottawa nodes contact me Bell: (613) 237-5629 + about joining ocunix.on.ca! -- :!mcr!: | The postmaster never | So much mail, Michael Richardson | resolves twice. | so little time. HOME: mcr@sandelman.ocunix.on.ca Bell: (613) 237-5629 Small Ottawa nodes contact me about joining ocunix.on.ca!
cg@ami-cg.UUCP (Chris Gray) (03/12/91)
In article <06493.AA06493@babylon.rmt.sub.org> rbabel@babylon.rmt.sub.org (Ralph Babel) writes: [edited down, but you'll all remember it!] >This is not true! It's always the function that brings the >code into memory (e.g. LoadSeg()) that is supposed to keep >the code cache up to date, not the function to execute this >code (e.g. CreateProc()). The same code might be executed >several times (even concurrently), so clearing the cache >every time would be wasteful. > >These are the only legal ways of bringing code into memory: > >- ROM-code >- DAC_WORDWIDE >- DAC_BYTEWIDE >- DAC_NIBBLEWIDE >- MakeFunctions() >- MakeLibrary() >- SetFunction() >- LoadSeg() > >Putting an entry into the Captures/KickTags and rebooting >the system _might_ also be considered safe. 2.0 provides a >few additional functions (e.g. InternalLoadSeg()) plus some >cache control calls. > >Sorry, self-modifying code. Even if Leo did it. :-) Ralph is saying that the technique of building a SegList structure at run-time and then using it with CreateProc is self-modifying code. I won't argue the definition (I don't think it is, I think it is dynamically created code). The technique does not break on systems with caches, whereas the usual forms of self-modifying code will. If Commodore wants to explicitly say that the technique is invalid (Ralph suggested an alternative), that is their right, but they should be clear on why. It is NOT because it breaks on CPUs with caches, but because they don't want it done. There may be good reasons for not doing it, like future considerations of MMUs and execute-only status. I waited for someone else to jump on this, but nobody did, so I had too. I've likely just crossed in the postings with half-a-dozen other replies. -- Chris Gray alberta!ami-cg!cg or cg%ami-cg@scapa.cs.UAlberta.CA
rbabel@babylon.rmt.sub.org (Ralph Babel) (03/12/91)
In article <cg.7124@ami-cg.UUCP>, cg@ami-cg.UUCP (Chris Gray) writes: > Ralph is saying that the technique of building a SegList > structure at run-time and then using it with CreateProc is > self-modifying code. I won't argue the definition (I don't > think it is, I think it is dynamically created code). "dynamically-created code"? Chris, I guess you've been doing too much compiler development lately! :-) > The technique does not break on systems with caches, [...] I think it does. Here's the scenario: 1. Process P1 executes its code in memory chunk M; 2. Parts of chunk M will be loaded into the code cache; 3. Process P1 terminates; 4. The memory area occupied by P1's code segment (including chunk M) is released to the free-memory pool; 5. Process P2 allocates a fake seglist; let's assume this seglist happens to be located in chunk M; 6. The code to be executed is copied to M, but this copying does _not_ update the _code_ cache!!! 7. Since CreateProc() doesn't clear the code cache, it will read the _old_ code from process P1 when entering the fake seglist. > It is NOT because it breaks on CPUs with caches, It does break on CPUs with _separate_ code and data caches. Ralph
rbabel@babylon.rmt.sub.org (Ralph Babel) (03/13/91)
In article <752@tnc.UUCP>, m0154@tnc.UUCP (GUY GARNETT) writes: > In the example code from AmigaMail, the 'code' is a single > instruction which is built into a data structure. When it > is branched to, the code cache will miss (that location > has never been executed before; How do you know? The same memory region might have been part of a code hunk - and FreeMem() doesn't clear the code cache. > The method is also always safe if you invalidate the cache > right after you put a value in CodeHdr.Function; With the 2.0 cache support functions it's certainly a lot safer (and easier) than before, but just wait and see how many programs will fail nevertheless with the 68040's copyback cache enabled. Ralph
m0154@tnc.UUCP (GUY GARNETT) (03/13/91)
I don't think that the examples described previously are self-modifying code (at least, not from the point of view of a 680x0 family processor). The reason: Self modifying code (the kind which causes programs to break) is where some values got into the code cache, and then were changed (by whatever agency method; its not important). When the program goes back to re-execute the instruction (its probably inside some kind of loop), if the cache hits (probably) then we execute the old (before change) instruction (on a miss, everything works fine). In the example code from AmigaMail, the 'code' is a single instruction which is built into a data structure. When it is branched to, the code cache will miss (that location has never been executed before; yes, the value is in the DATA chache, but the two are separate entities). Therefore, the method should be safe, as long as each separate task to be launched has its own CodeHdr. If you try to re-use a CodeHdr (by stuffing a new value in CodeHdr.Function) then it *IS* self-modifying code, and may fail. The method is also always safe if you invalidate the cache right after you put a value in CodeHdr.Function; this will work no matter how many times you try to re-use the structure (of course, trying to re-use CodeHdr will probably have other side-effects as well). Wildstar
cg@ami-cg.UUCP (Chris Gray) (03/13/91)
In article <06545.AA06545@babylon.rmt.sub.org> rbabel@babylon.rmt.sub.org (Ralp >In article <cg.7124@ami-cg.UUCP>, cg@ami-cg.UUCP (Chris >Gray) writes: > >> Ralph is saying that the technique of building a SegList >> structure at run-time and then using it with CreateProc is >> self-modifying code. I won't argue the definition (I don't >> think it is, I think it is dynamically created code). > >"dynamically-created code"? Chris, I guess you've been doing >too much compiler development lately! :-) Naw - working full-time on a MUD for the Amiga - all interpreted. >> The technique does not break on systems with caches, [...] > >I think it does. Here's the scenario: > >1. Process P1 executes its code in memory chunk M; >2. Parts of chunk M will be loaded into the code cache; >3. Process P1 terminates; >4. The memory area occupied by P1's code segment (including > chunk M) is released to the free-memory pool; >5. Process P2 allocates a fake seglist; let's assume this > seglist happens to be located in chunk M; >6. The code to be executed is copied to M, but this copying > does _not_ update the _code_ cache!!! >7. Since CreateProc() doesn't clear the code cache, it will > read the _old_ code from process P1 when entering the > fake seglist. > >> It is NOT because it breaks on CPUs with caches, > >It does break on CPUs with _separate_ code and data caches. Ok, you win - I wuz wrong. Sigh. In reality I would guess that the I-cache is flushed by CreateProc and/or LoadSeg, so it wouldn't matter, but I agree we are talking principles here. -- Chris Gray alberta!ami-cg!cg or cg%ami-cg@scapa.cs.UAlberta.CA
rbabel@babylon.rmt.sub.org (Ralph Babel) (03/14/91)
In article <19852@cbmvax.commodore.com>, jesup@cbmvax.commodore.com (Randell Jesup) writes: > If you build code yourself, a quick call to CacheClearE > with CACRF_ClearI will solve your day. With the 68040's copyback cache enabled, it won't. You have to push the data cache to memory as well. Ralph
jesup@cbmvax.commodore.com (Randell Jesup) (03/14/91)
45@babylon.r <cg.7176@ami-cg.UUCP> Sender: Reply-To: jesup@cbmvax.commodore.com (Randell Jesup) Followup-To: Distribution: Organization: Commodore, West Chester, PA Keywords: In article <cg.7176@ami-cg.UUCP> cg@ami-cg.UUCP (Chris Gray) writes: >In article <06545.AA06545@babylon.rmt.sub.org> rbabel@babylon.rmt.sub.org (Ralp >>"dynamically-created code"? Chris, I guess you've been doing >>too much compiler development lately! :-) > >Naw - working full-time on a MUD for the Amiga - all interpreted. Hmmmm. >>It does break on CPUs with _separate_ code and data caches. > >Ok, you win - I wuz wrong. Sigh. In reality I would guess that the I-cache >is flushed by CreateProc and/or LoadSeg, so it wouldn't matter, but I agree >we are talking principles here. In 2.0, LoadSeg flushes the ICache after relocation, and CreateNewProc flushes if it has to build any code you you (NP_Entry). If you build code yourself, a quick call to CacheClearE with CACRF_ClearI will solve your day. It even takes a start location and length. -- Randell Jesup, Keeper of AmigaDos, Commodore Engineering. {uunet|rutgers}!cbmvax!jesup, jesup@cbmvax.commodore.com BIX: rjesup The compiler runs Like a swift-flowing river I wait in silence. (From "The Zen of Programming") ;-)
peter@sugar.hackercorp.com (Peter da Silva) (03/14/91)
In article <cg.7124@ami-cg.UUCP> cg@ami-cg.UUCP (Chris Gray) writes: > The technique does not break on systems with caches, whereas the usual forms > of self-modifying code will. Sure. What if your newly-allocated seglist just happens to be sitting in a chunk of memory that an unloaded segment of code just vacated? -- Peter da Silva. `-_-' <peter@sugar.hackercorp.com>.
dillon@overload.Berkeley.CA.US (Matthew Dillon) (03/17/91)
In article <1991Mar14.203146.20908@Sandelman.OCUnix.On.Ca> mcr@Sandelman.OCUnix.On.Ca (Michael Richardson) writes: >In article <06493.AA06493@babylon.rmt.sub.org> cbmvax.commodore.com!cbmehq!babylon!rbabel (Ralph Babel) writes: >>In article <1991Mar9.170859.4810@Sandelman.OCUnix.On.Ca>, >>mcr@Sandelman.OCUnix.On.Ca (Michael Richardson) writes: >>... > No dispute about it being not exactly kosher. I had assumed that the >... I generally write a separate .A (assembly) file which BEGINS with the dummy segment... you get longword alignment AUTOMATICALLY because ALL OBJECT MODULES ARE LONGWORD ALIGNED! There is no need for CNOP or any other possibly screwy opcode (many assemblers will insert 0's instead of NOP's to do the alignment) -Matt -- Matthew Dillon dillon@Overload.Berkeley.CA.US 891 Regal Rd. uunet.uu.net!overload!dillon Berkeley, Ca. 94708 USA