justice@isucs1.UUCP (10/15/85)
Ok you wizards out there, why does this program do what it does? Here are a couple of hints: 1) It only works on Vaxes 2) The same idea is used to initialize the UNIBUS adapters --------------Here is a script showing the details------------------------ Script started on Mon Oct 14 14:08:05 1985 % cat reg.c main() { register int x, y; int i; int func(); fix((int *)func); x = 1; y = 5; for (i = 1; i <= 10; i++) { func(1,5); printf("x = %d, y = %d\n",x,y); } } func(x,y) int x,y; { register int a,b; a += a; b *= 5; x--; y++; } fix(f) int *f; { *f &= ~0xc00; } % cc reg.c -N -o reg % reg x = 2, y = 25 x = 4, y = 125 x = 8, y = 625 x = 16, y = 3125 x = 32, y = 15625 x = 64, y = 78125 x = 128, y = 390625 x = 256, y = 1953125 x = 512, y = 9765625 x = 1024, y = 48828125 % exit % script done on Mon Oct 14 14:08:29 1985 -------------------------------------------------------------------------- Good luck! Brian Justice, Iowa State University UUCP: {okstate||umn-cs||csu-cs}!isucs1!justice CSNET: justice@iowa-state
laman@ncr-sd.UUCP (Mike Laman) (10/17/85)
In article <468@isucs1.UUCP> justice@isucs1.UUCP writes: > >Ok you wizards out there, why does this program do what it does? >Here are a couple of hints: > 1) It only works on Vaxes : >main() : > int func(); > > fix((int *) func); : >fix(f) >int *f; >{ > *f &= ~0xc00; >} : Someone else will probably answer this before me -- we always seem to lag behind on the news. I apologize if someone else has answered it "already". The routine "fix" is modifying a mask that tells the "calls" (and friends) instruction which registers (if any) to save ON A VAX 11/780 (and friends). The mask is kept in the "first word" of the function which is where "func" points. "Fix" is changing the mask so registers 11 and 10 will NOT be saved/restored across function calls. On the VAX the UNIX C compiler allocates register 11 for the first register variable, then decreasing number in order of allocation of registers. This means the first two register variables (if the compiler see fit to use them as registers -- that's another story) will get overwritten in the calling routine ("main") every time it calls the routine that was "fixed", namely "func". In other words "func" is modifying "main"'s register variables. And I thought all that assembly I played with a year ago would be just a useless effort in futility :-). Mike Laman, NCR Rancho Bernardo UUCP: {ucbvax,philabs,sdcsla}!sdcsvax!ncr-sd!laman
ghr@wucs.UUCP (George Robbert) (10/19/85)
>Ok you wizards out there, why does this program do what it does? >Here are a couple of hints: > 1) It only works on Vaxes > 2) The same idea is used to initialize the UNIBUS adapters >main() >{ > register int x, y; > int i; > int func(); > > fix((int *)func); > x = 1; y = 5; > for (i = 1; i <= 10; i++) { > func(1,5); > printf("x = %d, y = %d\n",x,y); > } >} >func(x,y) >int x,y; >{ > register int a,b; > > a += a; b *= 5; > x--; y++; >} > >fix(f) >int *f; >{ > *f &= ~0xc00; >} >% cc reg.c -N -o reg >% reg >x = 2, y = 25 >x = 4, y = 125 >x = 8, y = 625 >x = 16, y = 3125 >x = 32, y = 15625 >x = 64, y = 78125 >x = 128, y = 390625 >x = 256, y = 1953125 >x = 512, y = 9765625 >x = 1024, y = 48828125 >Brian Justice, Iowa State University >UUCP: {okstate||umn-cs||csu-cs}!isucs1!justice CSNET: justice@iowa The reason that you get the strange behavior of x and y is due to fix's clearing 2 bits of the register save mask for func(). All functions on the VAX begin with a word (16 bit) that is the register save mask. This word indicates which registers should be pushed on the stack at function call time and restored on return. Bit n set corresponds to saving register n. Therefore, *f &= ~0xc00; clears the mask for r10 and r11. These just happen to be the two registers that x and y are stored in. They also happen to be the ones that a and b are stored in. Thus, since they are not saved and restored when func(1,5) is called, the changes to a and b are actually changes to x and y. This is why the code does what it does on the VAX. I don't know why they do this to initialize unibus adapters. (except maybe to minimize function call overhead by reducing the registers saved & restored at each call.) George Robbert, Washington University ghr@wucs.UUCP ...!ihnp4!wucs!ghr
art@ACC.ARPA (10/24/85)
>>Ok you wizards out there, why does this program do what it does? >>Here are a couple of hints: >> 1) It only works on Vaxes >> 2) The same idea is used to initialize the UNIBUS adapters >>main() >>{ >> register int x, y; >> int i; >> int func(); >> >> fix((int *)func); >> x = 1; y = 5; >> for (i = 1; i <= 10; i++) { >> func(1,5); >> printf("x = %d, y = %d\n",x,y); >> } >>} >> ...... > .... >This is why the code does what it does on the VAX. I don't >know why they do this to initialize unibus adapters. (except maybe >to minimize function call overhead by reducing the registers saved & >restored at each call.) This is done by autoconfigure when calling the probe() routines in device drivers. The probe routine is supposed to make the device cause an interrupt. An interrupt catcher figures out what vector and priority level the interrupt used and places these in r10 and r11. When the interrupt catcher exits, the probe routine sees the local variables cvec and br (which "just happen" to be in r10 and r11) magically change. The purpose of the entry mask "fix" is to prevent the values in r10 and r11 from being destroyed when probe returns to autoconfigure. Autoconfigure has also defined cvec and br to be local variables in r10 and r11 so these end up reflecting what probe got. I've always felt that this is a real kludge in 4.2 that is very machine and even compiler dependent. I wonder why globals were not defined for this purpose. Oh well, this is only one of my irritations with 4.2's driver environment. "Art Berggreen"<Art@ACC.ARPA> ------
narten@purdue.ARPA (Thomas Narten) (10/24/85)
>I've always felt that this is a real kludge in 4.2 that is very >machine and even compiler dependent. I wonder why globals were >not defined for this purpose. Oh well, this is only one of my >irritations with 4.2's driver environment. Blatant machine and compiler dependencies are not limited to driver or even kernel code! The following line appears in the middle of ld.c with no comments anywhere explaining what is going on. asm("movc3 r8,(r11),(r7)"); At the very least, an ``ifdef vax'' would be appropriate. How would you like to port this kind of undocumented stuff to a new machine? Thomas Narten ----------