From: Hunter Goatley <goathunter@WKUVX1.BITNET>
Newsgroups: vmsnet.internals
Subject: Locking down C routines under Alpha
Date: Sun, 15 Nov 1992 19:04:38 CST
Organization: Macro32<==>Vmsnet.Internals Gateway
X-Gateway-Source-Info: Mailing List

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: <mahan@TGV.COM>

#
#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 <syidef.h>
#include <decc$library_include:builtins.h>
/*
 *      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