From: Chris_F_Chiesa@cup.portal.com
Newsgroups: comp.os.vms
Subject: Long-awaited $IMGACT example program: part 2 of 2
Date: Wed,  6 Jan 93 18:54:45 PST
Organization: The Portal System (TM)
Distribution: world

-+-+-+-+-+-+-+-+ START OF PART 2 -+-+-+-+-+-+-+-+
X`09IAC$V_WRITABLE`09If set, the image is writeable
X`09IAC$V_SHAREABLE`09If set, the specified image is a shareable image`20
X`09`09`09that is being activated as a piece of an executable
X`09`09`09image. This flag can only be used in a recursive call
X`09`09`09to the image activator
X`09IAC$V_PRIVILEGE`09If set, the executable image has amplified privileges.
X`09`09`09If this flag is set, the shareable image being
X`09`09`09activated must be installed as a known file. The flag
X`09`09`09IAC$V_SHAREABLE must also be set.
X`09IAC$V_MERGE`09If set, the image activator is directed to merge one
X`09`09`09executable image into the address space of another.
X`09`09`09When this flag is set, the user stack, the image I/O
X`09`09`09segment, and the privilege amplification flag are
X`09`09`09to be ignored. This flag must be set if the image
X`09`09`09activator is called from user mode.
X`09IAC$V_EXPRG`09If set, the _inadr_ argument does not give an actual
X`09`09`09address range, but merely indicates the address space
X`09`09`09(P0 space or P1 space) into which the image is to be
X`09`09`09mapped. This flag is only used during a merged image
X`09`09`09activation.
Xinadr`09Address of a two-longword array containing the virtual address range
X`09into which the image is to be mapped. This argument is usually omitted,
X`09in which case the address ranges designated by the image section
X`09descriptors in the image header are used.
Xretadr`09Address of a two-longword array to receive the starting and ending
X`09addresses into which the image was actually mapped.
Xident`09Address of a quadword containing the version number and matching
X`09criteria for a shareable image.
XThe last 3 arguments are similiar to the input argumetns for various other
Xmemory management system services that are described in Chapter 16.
X--- End VVI quote ---
X
X----- INCLUDED TEXT ENDS -----
$ CALL UNPACK README.TXT;7 606893441
$ create 'f'
X;+
X; TRYIT.MAR - Christopher F. Chiesa, 9-NOV-1992 (commented 17-DEC-1992)
X;
X;    Accept DCL command line, nibble off TRYIT verb and replace with`20
X;    COPY, and call the VMS COPY utility as a subroutine.  Based on`20
X;    Internet posting from Garry Wiegand (garry@oak.cadif.cornell.edu)
X;    on March 28, 1988 in comp.os.vms newsgroup.
X;
X;-
X;===========================================================================
X; MACRO LIBRARIES`20
X;===========================================================================
X;
X`09.LIBRARY`09\SYS$LIBRARY:LIB\
X;
X;===========================================================================
X; LOCAL MACROS
X;===========================================================================
X;+
X;   CHKSTS dest
X;     Branch to "dest" if R0 contains a non-success severity condition`20
X;     value
X;-
X`09.MACRO`09CHKSTS,DEST,?LABEL`09; W.Dick
X`09BLBS`09R0,LABEL
X`09.IF`09NOT_BLANK,<DEST>
X`09BRW`09DEST
X`09.IF_FALSE
X`09RET
X`09.ENDC
XLABEL:
X`09.ENDM`09CHKSTS
X;+
X;   GEN_ASCID size
X;    Declare an "empty" descriptor of "size" characters
X;-
X`09.MACRO`09GEN_ASCID`09SIZE`09; C.Chiesa after R. & L. Utter
X`09x = .
X`09.ASCID`09\ \
X`09.BLKB`09<SIZE-1>
X`09y = .
X`09. = x
X`09.WORD`09<SIZE>
X`09. = y
X`09.ENDM`09GEN_ASCID
X;===========================================================================
X; SYMBOLIC CONSTANTS
X;===========================================================================
X`09cr = 13`09`09`09`09; Carriage Return character
X`09lf = 10`09`09`09`09; Line Feed character
X`09$SSDEF`09`09`09`09; Completion status values
X`09$UAIDEF`09`09`09`09; $GETUAI item codes
X`09$IACDEF`09`09`09`09; Image Activator symbols
X`09$IHDDEF`09`09`09`09; Image Header symbols
X;===========================================================================
X; WRITEABLE DATA
X;===========================================================================
X`09.PSECT`09DATA`09WRT,NOEXE
X;+
X; Item List (item_list_3) for $GETJPI
X;-
Xjpi_items:
X`09.word`0912`09`09`09; buffer length
X`09.word`09JPI$_USERNAME`09`09; $GETJPI item code
X`09.address username_data`09`09; buffer address
X`09.address username_desc`09`09; return length address
X`09.long`090
X;+
X; Item List (item_list_3) for $GETUAI
X;-
Xuai_items:
X`09.word`0932`09`09`09; buffer length
X`09.word`09UAI$_CLITABLES`09`09; $GETJPI item code`20
X`09.address cli_table_filename`09; buffer address
X`09.address cli_table_desc`09`09; return length address
X`09.long`090
X;+
X; Descriptor for username - LENGTH field receives $GETJPI buffer-length retu
Vrn
X;-
Xusername_desc:
X`09.long`0912`09`09`09; Username has 12 characters max
X`09.address username_data`09`09; Pointer to data buffer
Xusername_data:
X`09.blkb`0912`09`09`09; Data buffer
X;+
X; Descriptor for CLI table file name - LENGTH field receives $GETUAI`20
X; buffer-length return
X;-
Xcli_table_desc:
X`09.blkl
X`09.address`09cli_table_filename
Xcli_table_filename:
X`09.blkb`0932
X;+
X; Descriptor for COPY command constructed from TRYIT command that got us
X; into this program
X;-
Xcopy_command:`09`09`09`09; Receives entire command
X`09gen_ascid`09255
Xcopy:`09.ascid`09\COPY \`09`09`09; Actual COPY verb for DCL parse`09
X;+
X; Pointers to address range SYS$SYSTEM:COPY.EXE "wants" to reside in, i.e.
X; where it would find itself if invoked normally by DCL.  Note that this
X; is the same range where TRYIT.EXE would reside if linked without the`20
X; BASE=%XA000 statement in TRYIT.OPT; that statement and file exist solely
X; to "move TRYIT up out of the way" so that COPY can reside where it be-
X; longs. This is necessary because $IMGACT/$IMGFIX don't resolve address
X; references COMPILED INTO static descriptors...
X;-
Xcopy_home_range:`09`09`09; Address range COPY.EXE "wants"`20
X`09.address `5Ex00000200`09`09; to inhabit
X`09.address `5Ex00009DFF
X;+
X; Receives "actual" address range into which COPY.EXE gets mapped at run`20
X; time
X;+
Xvm_actual:
X`09.blka
X`09.blka
X;+
X; Receives address of DCL command table
X;-
Xcli_table_ptr:
X`09.blka
X;+
X; Buffer to contain header of COPY.EXE when $IMGACT'ed into memory
X;-
Ximg_header_buf:
X`09.blkb`09512
X;+
X; Messages - output BEFORE and AFTER calling COPY.EXE, to prove that TRYIT
X; is in control throughout!
X;-
Xafter_msg:`09.ascid`09<CR><LF>\* After calling COPY *\<CR><LF>
Xbefore_msg:`09.ascid`09<CR><LF>\* Before calling COPY *\<CR><LF>
X;+
X; Universal Symbol pointing to start of DCL Command Table in a DCL Command`2
V0
X; Table image file such as DCLTABLES.EXE:
X;-
Xcli_table_symbol:
X`09`09.ascid`09\DCL$AL_TAB_VEC\
X;+
X; CLI$ parameter name that gets us the "entire command line" from DCL:
X;-
Xline_parm:`09.ascid`09\$LINE\
X;+
X; Buffer to contain actual command line from DCL...
X;-
Xcommand_line:`09gen_ascid 255
X;+
X; Name of image file we're going to activate... the VMS Copy Utility!
X;-
Xcopy_image_name:
X`09`09.ascid`09\SYS$SYSTEM:COPY.EXE\
X;===========================================================================
X; EXECUTABLE CODE
X;===========================================================================
X`09.PSECT`09CODE`09NOWRT,EXE
X`09.DISABLE`09LOCAL_BLOCK
X`09.ENTRY`09TRYIT,`5EM<>
X;+
X; Issue "before" message
X;-
X`09pushaq`09before_msg
X`09calls`09#1,g`5ELIB$PUT_OUTPUT
X`09chksts`09try_fail
X;+
X; Get TRYIT command line...
X;-
X`09pushaw `09command_line
X`09pushaq`09command_line
X`09pushaq`09line_parm
X`09calls`09#3,g`5ECLI$GET_VALUE
X`09chksts`09try_fail
X`09subw2`09#1,command_line
X;+
X; "... nibble off the command verb..." (in this case, "TRYIT") ...
X;-
X`09.ENABLE`09LOCAL_BLOCK
X`09movl`09#SS$_BADPARAM,r0`09`09; Assume failure to nibble verb
X`09movaq`09command_line,r6`09`09`09; R6 <- line descr base
X`09locc`09#`5Ea\ \,DSC$W_LENGTH(r6),-`09; Find first blank if any
X`09`09@DSC$A_POINTER(r6)
X`09bneq`0910$
X`09brw`09try_fail
X10$:
X`09addl3`09#1,r1,DSC$A_POINTER(r6)
X`09bgtr`0920$
X`09brw`09try_fail
X20$:
X;+
X; Replace former TRYIT verb with COPY:
X;-
X`09addw3`09<command_line+DSC$W_LENGTH>,-
X`09`09<copy+DSC$W_LENGTH>,-
X`09`09<copy_command+DSC$W_LENGTH>
X`09pushaq`09command_line`09`09`09; ... tail of TRYIT command...
X`09pushaq`09copy`09`09`09`09; "COPY"
X`09pushaq`09copy_command`09`09`09; Receives concatenated string
X`09calls`09#3,g`5ESTR$CONCAT
X`09chksts`09try_fail
X;+
X; Look up username currently running this program
X;-
X`09$GETJPI_S -`09`09`09`09; username_desc gets filled in
X`09`09itmlst=jpi_items`09`09; with current username string
X`09chksts`09try_fail
X;+
X; Look up DCL command table file name for the username currently running thi
Vs
X; program; $GETUAI looks up this information in the system UAF (User Authori
V-
X; zation File):
X;-
X`09$GETUAI_S -`09`09`09`09; cli_table_desc gets filled in
X`09`09usrnam=username_desc,-`09`09; with command-table-filename
X`09`09itmlst=uai_items`09`09; string, with prefixed LENGTH
X`09`09`09`09`09`09; byte!
X`09chksts`09try_fail
X`09movzbw`09cli_table_filename,-`09`09; Copy filename length byte from
X`09`09cli_table_desc`09`09`09; string to descriptor
X`09movab`09<cli_table_filename+1>,-`09; Adjust valid filename string
X`09`09<cli_table_desc+DSC$A_POINTER>`09; data start address
X;+
X; Find the Universal Symbol "DCL$AL_TAB_VEC" in the named DCL command table
X; file, and merge that command table into process memory space and obtain`20
X; the address where the table is merged...
X;-
X`09pushal`09cli_table_ptr`09`09`09; Receives address of table
X`09pushaq`09cli_table_symbol`09`09; "DCL$AL_TAB_VEC"
X`09pushaq`09cli_table_desc`09`09`09; DCL command table filespec
X`09calls`09#3,g`5ELIB$FIND_IMAGE_SYMBOL
X`09chksts`09try_fail
X;+
X; Activate COPY using $IMGACT -- *THIS IS TOTALLY UNSUPPORTED BY DIGITAL!*
X;-
X`09$IMGACT_S -
X`09`09NAME=copy_image_name,-
X`09`09HDRBUF=img_header_buf,-
X`09`09IMGCTL=#<IAC$M_MERGE>,-
X`09`09INADR=copy_home_range,-
X`09`09RETADR=vm_actual
X`09chksts`09try_fail
X;+
X; Perform address fixups?  It's not clear what this does, but it seems to
X; be necessary.
X;-
X`09$IMGFIX_S
X;+
X; $IMGACT places COPY.EXE's Image Header in img_header_buf, and maps the`20
X; executable etc. portion(s) of the image at their "natural" addresses.
X; We have to traverse through the Image Header to find the address of the
X; entry mask of the entry point of COPY.EXE.  This is in one of the three
X; Transfer Vector fields, probably the first or second, but I tried to be
X; thorough and check for Debugger startup (SYS$IMGSTA), missing (0), and
X; other "wrong" Transfer Vector field contents...
X;-
X`09moval`09img_header_buf,r2`09`09; R2 => header buffer base
X`09movl`09(r2),r2`09`09`09`09; R2 => Image Header base
X;+
X; Look up offset, and compute actual address, of Transfer Vector array:
X;-
X`09movzwl`09IHD$W_ACTIVOFF(r2),r3`09`09; R3 <-- xfer array offset
X`09movab`09(r2)`5Br3`5D,r3`09`09`09; R3 <-- xfer array address
X;+
X; Look for first non-zero, non-SYS$IMGSTA transfer address, which we'll
X; assume is the proper start address for COPY.EXE:
X;-
X`09movl`09#0,r4`09`09`09`09; R4 <-- array index
Xloop:
X`09movab`09(r3)`5Br4`5D,r5`09`09`09; R5 <-- xfer address address
X`09movl`09(r5),r6`09`09`09`09; R6 <-- xfer address itself
X`09tstl`09r6`09`09`09`09; Is xfer address 0?
X`09beql`09next_entry`09`09`09;   YES: try next entry if any
X`09cmpl`09r6,#SYS$IMGSTA`09`09`09;    NO: is it $IMGSTA ?
X`09bneq`09go_for_it`09`09`09;       NO: try running image!
X;+
X; Repeat checks for all three entries in Transfer Vector array; if no usable
X; Transfer Address is found, indicate generic error (R0 = 0) and exit!
X;-
Xnext_entry:
X`09addl2`09#4,r4
X`09cmpl`09r4,#12`09`09`09`09; Past end of entries?
X`09blss`09loop`09`09`09`09;   NO: try again
X`09movl`09#0,r0`09`09`09`09;  YES: fail
X`09brw`09try_fail
X;+
X; Now that we know where COPY.EXE's entry point is, we can parse the COPY
X; command we constructed from the TRYIT command line, to make COPY.EXE`20
X; think IT is running directly from the command line!
X;-
Xgo_for_it:
X;+
X; Parse fake, "constructed" COPY command
X;-
X`09pushl`09cli_table_ptr
X`09pushaq`09copy_command
X`09calls`09#2,g`5ECLI$DCL_PARSE
X`09chksts`09try_fail
X;+
X; Call COPY.EXE as a subroutine!
X;-
X`09calls`09#0,(r6)`09`09`09`09; call COPY!
X`09movl`09r0,r5`09`09`09`09; R5 <- saved status from COPY
X;+
X; Show the world that TRYIT is still in control
X;-
X`09pushaq`09after_msg
X`09calls`09#1,g`5ELIB$PUT_OUTPUT`09`09; Generates its own status in
X`09`09`09`09`09`09; R0, which we ignore
X`09movl`09r5,r0`09`09`09`09; Restore saved COPY status
X;+
X; At this point, I am not aware that I need do anything special in order`20
X; to "unwind" anything I've done: there's no '$IMGDAC' (Image De-Activate)
X; operation, for example.  Everything gets unmapped, I presume, by the defau
Vlt
X; image rundown procedure(s).  As the original 1988 posting says, "trapping
X; possible $EXIT_S calls..." from COPY.EXE "... is left as an exercise for
X; the reader."
X;-
Xtry_fail:
X`09ret`09`09`09`09`09; Return to DCL with status
X`09.end`09tryit
$ CALL UNPACK TRYIT.MAR;22 863771829
$ create 'f'
XBASE=%XA000
$ CALL UNPACK TRYIT.OPT;1 67855631
$ create 'f'
Xdefine verb tryit
X  image testdir:tryit
X  parameter p1
X`09value(type=$rest_of_line)
$ CALL UNPACK TRYIT.CLD;7 1175010657
$ v=f$verify(v)
$ EXIT