From: MERC::"uunet!WKUVX1.BITNET!MacroMan" 15-NOV-1992 20:22 15-NOV-1992 20:22:00.00 To: macro32@WKUVX1.BITNET CC: Subj: Locking down C routines under Alpha Patrick Mahan (mahan@TGV.COM) sent me the following message and asked me to forward it to MACRO32. Hunter ------ Hunter Goatley, VMS Systems Programmer, Western Kentucky University goathunter@WKUVX1.BITNET, 502-745-5251 --------------------------------------------------------------------------- Date: Sun, 15 Nov 92 16:44:44 PST From: # #gleason@mwk.uucp writes: #> #> OK, got my Alpha station, and I'm converting reams of MACRO-32 to #>C, learning C as I go (and this gives me plenty of practice reading #>Alpha crash dumps ;-) ). #> #Fun, isn't it? 8-) # LDL, LDL, LDL, LDL, LDL, STO, LDL, LDL, LDL (yea, almost like a song ;-)). # #> In many of these programs, entire routines need to be locked in the #>working set. #> #> In the original MACRO program, all I had to do was something like... #[...] #> What's the best way to do the equivalent in C? Getting the start #>address is not so hard...(int*)&funcname seems to be adequate...but #>I don't know how to get the ending address... #> #The only way I've been able to do it is by putting another (possibly #void) routine after the one you want. # Correct. Under VAX C you can used stub procedures to bracket the code you want to lock down. # #Note however that this still doesn't do what you want/need to do. #Under Alpha, the address of the function is actually the address of #the procedure descriptor for that function. Specifying those #addresses just locks down the procedure descriptor, which needs to be #done, but you must also still lock down the code itself. # #With the Alpha porting toolkit, there is a MACRO-32 example in the #_Porting MACRO-32 Code_ (whatever it's really called). It uses some #new macros to lock things down: $LOCKED_PAGE_START and #$LOCKED_PAGE_END. There's also $LOCK_PAGE and $LOCK_PAGE_INIT, but #I'm not sure how they're used. The macros are not available for #anything except MACRO-32, as far as I can tell. # #Another manual (_Recompiling and Relinking_) talked about this #problem, but the C example was "To be supplied" in all the field test #documentation. I haven't had time to take the macros and figure #out how to do it for C. # The way to perform this same feat under GEM C on the Alpha is in three steps. 1) Place all of the code that needs to be locked down inside of one or more code modules where they WILL NOT share with code that doesn't need to be locked down. Now using the CLUSTER link option, create 3 clusters in your image like so CLUSTER=START_OF_LOCKED_CODE CLUSTER=LOCKED_CODE,,,LOCKED_CODE.OBJ CLUSTER=END_OF_LOCKED_CODE Using the COLLECT link option, place a symbol in the clusters START_OF_LOCKED_CODE and END_OF_LOCKED_CODE so that you can later reference them, for example: COLLECT=START_OF_LOCKED_CODE,START_OF_CODE COLLECT=END_OF_LOCKED_CODE,END_OF_CODE You now have two references that bracket the code, including the linkage sections, that you want to lock down. 2) In the routine you wish to lock the code down in, declare both "endpoints" of your lock code like so - extern START_OF_CODE(), END_OF_CODE(); However, you cannot just lock down everything in memory starting at START_OF_CODE and ending at END_OF_CODE because of the way the Alpha linker works. On the Alpha, the linker does some page aligning which will cause "holes" in your image, this side effect is documented in the RECOMPILING_RELINKING manual provided with the cross tools. Instead, first retrieve the system PAGE SIZE via a call to $GETSYI using the item code (SYI$_PAGE_SIZE). Then starting with the address pointed to by START_OF_CODE, first check to see if the page is readable using the C builtin __PAL_PROBER instruction. If it is readable, then lock that page down, and move on to the next page in memory. Repeat this until you have reached the address pointed to by END_OF_CODE. Below is a C routine I wrote to lock down all of the known pages between two addresses. #include #include /* * Lock pages in memory for Alpha. We do this because the address * space we want to lock down is not contiguous. Thus we probe * each page for Read then lock it down. */ int Lock_Alpha_Pages(Addr_Start, Addr_End) char *Addr_Start, *Addr_End; { int i; unsigned long int Page_Size; unsigned long int InAddr[2]; char Error[200]; struct { unsigned short int Size; unsigned short int Code; char *Buffer; unsigned short int *Resultant_Length; } ItemList[2]; /* * Get the PAGE SIZE of the System */ ItemList[0].Size = sizeof(Page_Size); ItemList[0].Code = SYI$_PAGE_SIZE; ItemList[0].Buffer = (char *)&Page_Size; ItemList[0].Resultant_Length = 0; ItemList[1].Size = 0; ItemList[1].Code = 0; if (!(i = SYS$GETSYI(0, 0, 0, ItemList, 0, 0, 0) & 1)) { return (i); } /* * From Start Address until End Address, probe and * lockdown the pages */ for (InAddr[0] = (unsigned long int)Addr_Start; InAddr[0] < (unsigned long int)Addr_End; InAddr[0] = InAddr[0] + Page_Size) { /* * Set up the input address range */ InAddr[1] = InAddr[0] + Page_Size - 4; /* * Probe the page for 4 bytes */ i = __PAL_PROBER((void *)InAddr[0], 4, 0); /* * Check for probe success */ if (!(i & 1)) continue; /* * Lock the Page down */ i = sys$lkwset(InAddr, 0, 0); if (!(i & 1)) { return(i); } } /* * Done, return success */ return(1); } This should allow you to lock down any code you need. Patrick L. Mahan --- TGV Window Washer ------------------------------- Mahan@TGV.COM --------- Waking a person unnecessarily should not be considered - Lazarus Long a capital crime. For a first offense, that is From the Notebooks of