Return proper based_entry structure from hcs_$make_entry() rather than int
authorNick Downing <nick@ndcode.org>
Fri, 25 Oct 2019 14:14:02 +0000 (01:14 +1100)
committerNick Downing <nick@ndcode.org>
Fri, 25 Oct 2019 14:14:14 +0000 (01:14 +1100)
multics_sim.c
pl1/link_snap.pl1 [new file with mode: 0644]

index 20ad935..502fa57 100644 (file)
@@ -47,6 +47,14 @@ struct arg_desc {
   uint64_t dummy0 : 28;
 };
 
+// dcl 01 based_entry aligned based,
+struct based_entry {
+  // 02 code_ptr ptr,
+  struct its_pointer code_ptr;
+  // 02 env_ptr ptr;
+  struct its_pointer env_ptr;
+};
+
 #define N_PATHS 7
 char *paths[N_PATHS] = {
   "tape/word/library_dir_dir/system_library_1/execution/",
@@ -628,7 +636,7 @@ void emcall_make_entry(void) {
   uint64_t *entry_point_name = (uint64_t *)(
     M[arg_list->args[2].segment] + arg_list->args[2].address
   );
-  uint64_t *entry_point = (uint64_t *)(
+  struct based_entry *entry_point = (struct based_entry *)(
     M[arg_list->args[3].segment] + arg_list->args[3].address
   );
   uint64_t *code = (uint64_t *)(
@@ -641,7 +649,7 @@ void emcall_make_entry(void) {
   char entry_point_name_buf[NAME_LEN + 1];
   get_string_rstrip(entry_point_name_buf, entry_point_name, NAME_LEN);
 
-  *entry_point = (
+  entry_point->code_ptr =
     entry_point_name_buf[0] ?
       find_definition(
         link_segment(entryname_buf),
@@ -649,16 +657,17 @@ void emcall_make_entry(void) {
         -1,
         false
       ) :
-      its_pointer(make_known(entryname_buf)->segment, 0)
-  ).address;
+      its_pointer(link_segment(entryname_buf)->segment, 0);
+  entry_point->env_ptr = its_pointer(-1, 1);
   *code = 0;
 
   fprintf(
     stderr,
-    "make_entry %s$%s -> %06o\n",
+    "make_entry %s$%s -> %06o:%06o\n",
     entryname_buf,
     entry_point_name_buf,
-    (int)*entry_point
+    entry_point->code_ptr.segment,
+    entry_point->code_ptr.address
   );
 }
 
@@ -815,7 +824,7 @@ int main(int argc, char **argv) {
   // initialize CPU
   sim_deb = stderr;
   cpu_dev.dctrl =
-    DBG_TRACE |
+    //DBG_TRACE |
     //DBG_MSG |
     //DBG_REGDUMPAQI |
     //DBG_REGDUMPIDX |
@@ -1133,7 +1142,6 @@ int main(int argc, char **argv) {
     abort();
   }
 
-#if 0
   // call requested entry
   fprintf(stderr, "call %s$%s\n", entry_segname, entry_name);
 
@@ -1238,7 +1246,6 @@ int main(int argc, char **argv) {
     get_string(buf, result, result_len);
     printf("%s\n", buf);
   }
-#endif
 
   return 0;
 }
diff --git a/pl1/link_snap.pl1 b/pl1/link_snap.pl1
new file mode 100644 (file)
index 0000000..c85bc7c
--- /dev/null
@@ -0,0 +1,2093 @@
+/****^  ***********************************************************
+        *                                                         *
+        * Copyright, (C) Honeywell Bull Inc., 1987                *
+        *                                                         *
+        * Copyright, (C) Honeywell Information Systems Inc., 1986 *
+        *                                                         *
+        *********************************************************** */
+
+
+
+
+/****^  HISTORY COMMENTS:
+  1) change(86-05-02,Elhard), approve(86-05-02,MCR7391),
+     audit(86-07-18,DGHowe), install(86-11-20,MR12.0-1222):
+     Rewritten to support object multisegment files.  In particular, support
+     of indirect definitions, deferred initialization, partial links, and
+     preliminary support for *heap links.
+  2) change(86-06-24,DGHowe), approve(86-06-24,MCR7396),
+     audit(86-11-05,Elhard), install(86-11-20,MR12.0-1222):
+     added a check for heap links and a call to set_ext_variable_$star_heap
+     when a heap link is found.
+  3) change(86-06-24,DGHowe), approve(86-06-24,MCR7420),
+     audit(86-11-05,Elhard), install(86-11-20,MR12.0-1222):
+     added a segment pointer to the calling sequences of for_linker and
+     star_heap for ext pointer initialization.
+  4) change(87-06-10,Elhard), approve(87-07-17,MCR7739),
+     audit(87-06-10,RWaters), install(87-07-17,MR12.1-1043):
+     Critical fix to correct snapping of CREATE_IF_NOT_FOUND (type 6) links to
+     targets with no offset name, or nonexistent targets.
+                                                   END HISTORY COMMENTS */
+
+
+/* format: style1,insnl,ifthendo,indthenelse,^indnoniterdo,^inditerdo,indcom,^indthenbegin,^indprocbody,ind2,ll79,initcol0,dclind4,idind24,struclvlind1,comcol41 */
+
+link_snap:
+  proc;
+
+  /*** ****************************************************************/
+  /***                                                 */
+  /*** Name:   link_snap                                       */
+  /*** Input:  none                                    */
+  /*** Function:       This procedure implements the Multics dynamic   */
+  /***         linking mechanism.  Four entries exist in this  */
+  /***         procedure:                              */
+  /***           link_snap$link_fault - This entry is called as        */
+  /***                              due to a fault_tag_2       */
+  /***                              (linkage) fault.   */
+  /***           link_snap$link_force - This entry corresponds */
+  /***                              to the hcs_$link_force     */
+  /***                              gate entry.  It basicly    */
+  /***                              duplicates the action of   */
+  /***                              a link_fault without       */
+  /***                              taking a fault.    */
+  /***           link_snap$make_ptr   - This entry corresponds */
+  /***                              to the hcs_$make_ptr       */
+  /***                              gate entry. It simulates   */
+  /***                              a type-3 or type-4 link    */
+  /***                              fault and returns the      */
+  /***                              target as a pointer.       */
+  /***           link_snap$make_entry - This entry corresponds */
+  /***                              to the hcs_$make_entry     */
+  /***                              gate entry. It simulates   */
+  /***                              a type-3 or type-4 link    */
+  /***                              fault and returns the      */
+  /***                              target as an entry value   */
+  /***                                                 */
+  /*** ****************************************************************/
+
+  /* constants */
+
+  dcl true             bit (1) static options (constant) init ("1"b);
+  dcl false            bit (1) static options (constant) init ("0"b);
+
+  dcl indirect         bit (6) static options (constant) init ("20"b3);
+
+  dcl Link_fault               fixed bin static options (constant) init (1);
+  dcl Link_force               fixed bin static options (constant) init (2);
+  dcl Make_ptr         fixed bin static options (constant) init (3);
+  dcl Make_entry               fixed bin static options (constant) init (4);
+
+  dcl No_retry         bit (1) static options (constant) init ("0"b);
+  dcl Will_retry               bit (1) static options (constant) init ("1"b);
+
+  dcl zero_word                bit (36) static options (constant) init (""b);
+
+  dcl None             fixed bin (18) unsigned unaligned
+                       static options (constant) init (0);
+
+  /* parameters */
+
+  dcl a_mcp            ptr parameter;
+  dcl a_link_pairp             ptr parameter;
+  dcl a_dummy          fixed bin parameter;
+  dcl a_code           fixed bin (35) parameter;
+  dcl a_refp           ptr parameter;
+  dcl a_seg_name               char (*) parameter;
+  dcl a_offset_name            char (*) parameter;
+  dcl a_targetp                ptr parameter;
+  dcl a_targete                entry parameter;
+
+  /* procedures */
+
+  dcl condition_               entry (char (*), entry);
+  dcl fs_search                entry (ptr, char (*), bit (1) aligned, ptr,
+                       fixed bin (35));
+  dcl fs_search$same_directory
+                       entry (ptr, char (*), ptr, fixed bin (35));
+  dcl get_defptr_              entry (ptr, ptr, ptr, ptr, fixed bin (35));
+  dcl level$get                entry () returns (fixed bin (3));
+  dcl level$set                entry (fixed bin (3));
+  dcl link_man$other_linkage   entry (ptr, ptr, ptr, ptr, fixed bin (35));
+  dcl link_man$own_linkage     entry (ptr, ptr, ptr, ptr, fixed bin (35));
+  dcl page$enter_data  entry (ptr unal, fixed bin);
+  dcl set_ext_variable_$for_linker
+                       entry (char (*), ptr, ptr, ptr, bit (1) aligned,
+                       ptr, fixed bin (35), ptr, ptr, ptr, ptr);
+  dcl set_ext_variable_$star_heap
+                       entry (char (*), ptr, ptr, ptr, bit (1) aligned,
+                       ptr, fixed bin (35));
+  dcl trap_caller_caller_      entry (ptr, ptr, ptr, ptr, ptr, ptr,
+                       fixed bin (35));
+  dcl usage_values             entry (fixed bin (30) aligned,
+                       fixed bin (71) aligned);
+
+  /* external */
+
+  dcl 01 ahd$link_meters       (4) aligned external like link_meters;
+  dcl error_table_$bad_class_def
+                       external fixed bin (35);
+  dcl error_table_$bad_deferred_init
+                       external fixed bin (35);
+  dcl error_table_$bad_indirect_def
+                       external fixed bin (35);
+  dcl error_table_$bad_link_type
+                       external fixed bin (35);
+  dcl error_table_$bad_self_ref
+                       external fixed bin (35);
+  dcl error_table_$first_reference_trap
+                       external fixed bin (35);
+  dcl error_table_$illegal_ft2
+                       external fixed bin (35);
+  dcl error_table_$no_defs     external fixed bin (35);
+  dcl error_table_$no_ext_sym external fixed bin (35);
+  dcl error_table_$no_linkage external fixed bin (35);
+  dcl error_table_$unexpected_ft2
+                       external fixed bin (35);
+  dcl pds$link_meters_bins     (4) external fixed bin (30);
+  dcl pds$link_meters_pgwaits (4) external fixed bin (30);
+  dcl pds$link_meters_times    (4) external fixed bin (35);
+  dcl pds$stacks               (0:7) external ptr;
+
+  /* based */
+
+  dcl 01 based_entry   aligned based,
+       02 code_ptr             ptr,
+       02 env_ptr              ptr;
+  dcl 01 expr          aligned like exp_word based (exprp);
+  dcl 01 link_pair             aligned like object_link based (link_pairp);
+  dcl 01 offsetname            aligned based (offsetnamep),
+       02 count                fixed bin (9) unsigned unaligned,
+       02 string               char (offsetname.count) unaligned;
+  dcl 01 segname               aligned based (segnamep),
+       02 count                fixed bin (9) unsigned unaligned,
+       02 string               char (segname.count) unaligned;
+  dcl 01 type_pr               aligned like type_pair based (type_prp);
+  dcl 01 usage         aligned based,
+       02 time         fixed bin (71),
+       02 pf           fixed bin (30);
+
+  /* automatic */
+
+  dcl 01 automatic_offsetname aligned automatic,
+       02 count                fixed bin (9) unsigned unaligned,
+       02 string               char (256) unaligned;
+  dcl 01 automatic_segname     aligned automatic,
+       02 count                fixed bin (9) unsigned unaligned,
+       02 string               char (32) unaligned;
+  dcl 01 call_info             aligned automatic,
+       02 type         fixed bin,
+       02 save_ring            fixed bin,
+       02 mcp          ptr,
+       02 codep                ptr,
+       02 start                aligned like usage,
+       02 finish               aligned like usage,
+       02 search               aligned like usage,
+       02 get_linkage  aligned like usage,
+       02 def_search   aligned like usage;
+  dcl call_infop               ptr automatic;
+  dcl code             fixed bin (35) automatic;
+  dcl connect_fail_code        fixed bin (35) automatic;
+  dcl defp             ptr automatic;
+  dcl exprp            ptr automatic;
+  dcl init_infop               ptr automatic;
+  dcl instrp           ptr automatic;
+  dcl link_pairp               ptr automatic;
+  dcl linkp            ptr automatic;
+  dcl nchars           fixed bin automatic;
+  dcl offset_name              char (256) automatic;
+  dcl offsetnamep              ptr automatic;
+  dcl refp             ptr automatic;
+  dcl retry_sw         bit (1) automatic;
+  dcl seg_name         char (32) automatic;
+  dcl segnamep         ptr automatic;
+  dcl segp             ptr automatic;
+  dcl star_system_sw   bit (1) automatic;
+  dcl target_linkagep  ptr automatic;
+  dcl targetp          ptr automatic;
+  dcl textp            ptr automatic;
+  dcl type_prp         ptr automatic;
+  dcl MSF_sw           bit (1) aligned automatic;
+
+  /* builtin */
+
+  dcl addr             builtin;
+  dcl addrel           builtin;
+  dcl baseno           builtin;
+  dcl baseptr          builtin;
+  dcl bin                      builtin;
+  dcl char             builtin;
+  dcl divide           builtin;
+  dcl index            builtin;
+  dcl length           builtin;
+  dcl ltrim            builtin;
+  dcl max                      builtin;
+  dcl min                      builtin;
+  dcl null             builtin;
+  dcl ptr                      builtin;
+  dcl rtrim            builtin;
+  dcl substr           builtin;
+  dcl unspec           builtin;
+
+  return;
+
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+\f
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+
+
+link_fault:
+  entry (a_mcp);                       /** machine conditions  (i/o)   */
+
+  /*** ****************************************************************/
+  /***                                                 */
+  /*** Name:   link_snap$link_fault                    */
+  /*** Input:  mcp                                     */
+  /*** Function:       handles a fault_tag_2 (linkage) fault.  The mcp */
+  /***         pointer points to the machine conditions at the */
+  /***         time of the fault.  If the link snapping is     */
+  /***         successfull, the machine conditions will be     */
+  /***         adjusted to allow the fault to be restarted.    */
+  /*** Output: mcp                                     */
+  /***                                                 */
+  /*** ****************************************************************/
+
+  /* copy the parameters into automatic storage */
+
+  mcp = a_mcp;
+
+  call_infop = addr (call_info);
+  call_info.type = Link_fault;
+  call_info.mcp = mcp;
+  call_info.save_ring = level$get ();
+
+  /* since this is a fault, the trap routines can't set a return code  */
+
+  call_info.codep = null;
+
+  /* set validation level to the level that the fault occurred at */
+
+  scup = addr (mc.scu (0));
+  call level$set (bin (scu.ppr.prr, 3));
+
+  /* get a pointer to the faulting link pair and instruction */
+
+  link_pairp = ptr (baseptr (bin (scu.tpr.tsr, 15)), scu.ca);
+  instrp = ptr (baseptr (bin (scu.ppr.psr, 15)), scu.ilc);
+
+  /* trace the fault */
+
+  call page$enter_data ((instrp), linkage_fault_start);
+
+  /* make sure the fault_tag_2 wasn't in an instruction */
+
+  if instrp -> its.its_mod = FAULT_TAG_2
+    then call exit (call_infop, error_table_$unexpected_ft2, null);
+
+  goto link_join;
+
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+\f
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+
+
+link_force:
+  entry (a_link_pairp,         /** ptr to link to snap (in )   */
+       a_dummy,                        /** unused          (---) */
+       a_code);                        /** error code      (out) */
+
+  /*** ****************************************************************/
+  /***                                                 */
+  /*** Name:   link_snap$link_force                    */
+  /*** Input:  link_pairp                              */
+  /*** Function:       given a pointer to a link, snap it without taking       */
+  /***         a fault.  This entry is functionally the same as        */
+  /***         link_snap$link_fault except that it is entered  */
+  /***         via gate call rather than fault entry.          */
+  /*** Output: code                                    */
+  /***                                                 */
+  /*** ****************************************************************/
+
+  /* not a fault entry */
+
+  mcp = null;
+
+  /* copy parameters into automatic storage */
+
+  link_pairp = a_link_pairp;
+
+  /* set up call info */
+
+  call_infop = addr (call_info);
+  call_info.type = Link_force;
+  call_info.mcp = null;
+  call_info.save_ring = -1;
+
+  /* save error code address in case we trap out to the user ring and  */
+  /* the trap procedure needs to set the error code.           */
+
+  call_info.codep = addr (a_code);
+
+  /* for a link_force call, we use the link itself as the start point  */
+  /* for tracing purposes.                                     */
+
+  call page$enter_data ((link_pairp), linkage_fault_start);
+
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+\f
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+
+
+link_join:
+
+  /* clear out the metering information */
+
+  call_info.search.time = 0;
+  call_info.search.pf = 0;
+  call_info.get_linkage.time = 0;
+  call_info.get_linkage.pf = 0;
+  call_info.def_search.time = 0;
+  call_info.def_search.pf = 0;
+
+  /* meter the fault time etc. */
+
+  call usage_values (call_info.start.pf, call_info.start.time);
+
+  if link_pair.tag ^= FAULT_TAG_2
+    then if call_info.type = Link_force
+        then call exit (call_infop, 0, baseptr (0));
+        else call exit (call_infop, error_table_$illegal_ft2, null);
+
+  /* get the linkage section and text pointers */
+
+  linkp = addrel (link_pairp, link_pair.header_relp);
+  textp = baseptr (linkp -> linkage_header.stats.segment_number);
+  target_linkagep = null;
+
+  /* validate the definition pointer */
+
+  if addr (linkp -> linkage_header.def_ptr) -> its.its_mod ^= ITS_MODIFIER
+    then call exit (call_infop, error_table_$no_defs, null);
+    else defp = linkp -> linkage_header.def_ptr;
+
+  /* validate that all first reference traps have been run */
+
+  if linkp -> virgin_linkage_header.first_ref_relp ^= 0
+    then call exit (call_infop, error_table_$first_reference_trap, null);
+
+  /* now that things look reasonably valid, we start decoding the link */
+
+  exprp = addrel (defp, link_pair.expression_relp);
+  type_prp = addrel (defp, expr.type_relp);
+
+  /* first we check the link to see if it should be converted into a   */
+  /* *system link.  Trap-before links to datmk_ and certain type-6     */
+  /* links are converted to *system links.                     */
+
+  call convert_trap_link (call_infop, linkp, defp, type_prp, offset_name,
+       init_infop, star_system_sw);
+
+  if star_system_sw
+    then do;
+
+      /* the link either was a *system link, or has become one */
+
+      call star_system (call_infop, link_pairp, defp, linkp, type_prp,
+        offset_name, init_infop, targetp);
+      call snap (targetp, (expr.expression), link_pairp);
+      call meter (call_infop, (type_pr.type));
+      call exit (call_infop, 0, targetp);
+    end;
+
+  /* see if we have a C *heap link */
+
+  if type_pr.type = LINK_SELF_OFFSETNAME & type_pr.segname_relp = CLASS_HEAP
+    then do;
+
+      /* C *heap links are similar to *system links except that they   */
+      /* are allocated separately, and have a level associated with    */
+      /* them so that recursive invocations get new copies and they    */
+      /* can be released when the invocation returns.          */
+
+      call star_heap (call_infop, defp, linkp, type_prp, targetp);
+      call snap (targetp, (expr.expression), link_pairp);
+      call meter (call_infop, (type_pr.type));
+      call exit (call_infop, 0, targetp);
+    end;
+
+  /* now see if there is a trap pointer.  Anything with a trap */
+  /* pointer that wasn't converted to a *system link, and isn't a      */
+  /* create link, we now treat as a trap-before link, and try to run   */
+  /* the trap.                                         */
+
+  if type_pr.type ^= LINK_CREATE_IF_NOT_FOUND & type_pr.trap_relp ^= None
+    then do;
+
+      /* actually is a trap-before link, trap out to the user  */
+      /* ring to execute the trap procedure.                   */
+
+      /* NB.  We don't try to complete tracing or metering in this     */
+      /*           case since it would be rather meaningless anyway. . .       */
+
+      call adjust_mc (mcp);
+      call trap_caller_caller_ (mcp, linkp, defp, type_prp, link_pairp,
+        call_info.codep, code);
+
+      /* usually we don't return, but. . . */
+
+      call exit (call_infop, code, baseptr (0));
+    end;
+
+  /* at this point we assume we have a reasonably standard link and    */
+  /* can just snap it according to type.                       */
+
+  if /* case */ type_pr.type = LINK_SELF_BASE
+    then do;
+      call self_reference (call_infop, (type_pr.segname_relp), textp,
+        targetp);
+      call snap (targetp, (expr.expression), link_pairp);
+      call meter (call_infop, (type_pr.type));
+      call exit (call_infop, 0, targetp);
+    end;
+
+  else if type_pr.type = LINK_OBSOLETE_2
+    then call exit (call_infop, error_table_$bad_link_type, null);
+
+  else if type_pr.type = LINK_REFNAME_BASE
+    then do;
+      segnamep = addrel (defp, type_pr.segname_relp);
+      if defp -> definition_header.msf_map_relp ^= None
+        then MSF_sw = true;
+        else MSF_sw = false;
+      call search_for_segment (call_infop, segnamep, textp, MSF_sw, segp,
+        code);
+      if segp = null
+        then call exit (call_infop, code, null);
+      call snap (segp, (expr.expression), link_pairp);
+      call meter (call_infop, (type_pr.type));
+      call exit (call_infop, 0, segp);
+    end;
+
+  else if type_pr.type = LINK_REFNAME_OFFSETNAME
+    then do;
+      segnamep = addrel (defp, type_pr.segname_relp);
+      if defp -> definition_header.msf_map_relp ^= None
+        then MSF_sw = true;
+        else MSF_sw = false;
+      call search_for_segment (call_infop, segnamep, textp, MSF_sw, segp,
+        code);
+      if segp = null
+        then call exit (call_infop, code, null);
+      call condition_ ("seg_fault_error", connect_fail_handler_);
+      call get_offsetnamep (call_infop, defp, type_prp, offsetnamep);
+      call get_definition (call_infop, segnamep, offsetnamep, segp,
+        No_retry, target_linkagep, targetp);
+      call snap (targetp, (expr.expression), link_pairp);
+      call meter (call_infop, (type_pr.type));
+      call trap (call_infop, target_linkagep, targetp);
+      call exit (call_infop, 0, targetp);
+    end;
+
+  else if type_pr.type = LINK_SELF_OFFSETNAME
+    then do;
+      call self_reference (call_infop, (type_pr.segname_relp), textp,
+        targetp);
+
+      /* insure that segname won't be found */
+
+      segnamep = addr (zero_word);
+      call get_offsetnamep (call_infop, defp, type_prp, offsetnamep);
+      call get_definition (call_infop, segnamep, offsetnamep, textp,
+        No_retry, (null), targetp);
+      call snap (targetp, (expr.expression), link_pairp);
+      call meter (call_infop, (type_pr.type));
+      call exit (call_infop, 0, targetp);
+    end;
+
+  else if type_pr.type = LINK_CREATE_IF_NOT_FOUND
+    then do;
+
+      /* NB.  since we have already processed the trap case, we will   */
+      /*           assume that this link can be treated as a type-4 until      */
+      /*           something breaks.                           */
+
+      segnamep = addrel (defp, type_pr.segname_relp);
+      if defp -> definition_header.msf_map_relp ^= None
+        then MSF_sw = true;
+        else MSF_sw = false;
+      call search_for_segment (call_infop, segnamep, textp, MSF_sw, segp,
+        code);
+      if segp = null
+        then do;
+
+       /* OK.  something broke.  now we try to treat this as a */
+       /* *system link so that the caller will get something.  */
+
+       call get_offsetnamep (call_infop, defp, type_prp, offsetnamep);
+       if offsetnamep = null
+         then offset_name = segname.string || "$";
+         else offset_name = segname.string || "$" || offsetname.string;
+       if type_pr.trap_relp = 0
+         then init_infop = null;
+         else init_infop = addrel (defp, type_pr.trap_relp);
+       call star_system (call_infop, link_pairp, defp, linkp, type_prp,
+            offset_name, init_infop, targetp);
+       call snap (targetp, (expr.expression), link_pairp);
+       call meter (call_infop, (type_pr.type));
+       call exit (call_infop, 0, targetp);
+        end;
+
+      call condition_ ("seg_fault_error", connect_fail_handler_);
+      call get_offsetnamep (call_infop, defp, type_prp, offsetnamep);
+
+      /* dont try to do a definition search if no entrypoint name was given */
+
+      if offsetnamep ^= null
+        then call get_definition (call_infop, segnamep, offsetnamep, segp,
+               No_retry, target_linkagep, targetp);
+        else targetp = segp;
+      call snap (targetp, (expr.expression), link_pairp);
+      call meter (call_infop, (type_pr.type));
+      call trap (call_infop, target_linkagep, targetp);
+      call exit (call_infop, 0, targetp);
+    end;
+
+  else call exit (call_infop, error_table_$bad_link_type, null);
+
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+\f
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+
+
+make_ptr:
+  entry (a_refp,                       /** referencing dir ptr (in )   */
+       a_seg_name,                     /** segname to find         (in ) */
+       a_offset_name,          /** entrypoint to find  (in ) */
+       a_targetp,                      /** target ptr returned (out) */
+       a_code);                        /** error code      (out) */
+
+  /*** ****************************************************************/
+  /***                                                 */
+  /*** Name:   link_snap$make_ptr                              */
+  /*** Input:  refp, seg_name, offset_name                     */
+  /*** Function:       Using the segname and optional offsetname given,        */
+  /***         snap a simulated type-3 (if a null offsetname)  */
+  /***         or type-4 (if non-null) link and return a pointer       */
+  /***         to the target.  The reference pointer is passed */
+  /***         to fs_search in order to evaluate the referencing       */
+  /***         dir search rule.  If it is null, the referencing        */
+  /***         dir rule is skipped.                    */
+  /*** Output: targetp, code                           */
+  /***                                                 */
+  /*** ****************************************************************/
+
+  /* preset the return values */
+
+  a_targetp = null;
+
+  /* set up the call info */
+
+  call_info.type = Make_ptr;
+
+  goto make_join;
+
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+\f
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+
+
+make_entry:
+  entry (a_refp,                       /** referencing dir ptr (in )   */
+       a_seg_name,                     /** segname to find         (in ) */
+       a_offset_name,          /** entrypoint to find  (in ) */
+       a_targete,                      /** entry returned          (out) */
+       a_code);                        /** error code      (out) */
+
+  /*** ****************************************************************/
+  /***                                                 */
+  /*** Name:   link_snap$make_entry                    */
+  /*** Input:  refp, seg_name, offset_name                     */
+  /*** Function:       performs the same function as link_snap$make_ptr        */
+  /***         except that an entry value is returned instead of       */
+  /***         a pointer value.  The other difference between  */
+  /***         calling make_entry and make_ptr is that if the  */
+  /***         offsetname value is null on a call to make_entry        */
+  /***         the target linkage section is combined and any  */
+  /***         first reference traps run.  This is because it is       */
+  /***         assumed that if you want an entry returned, you */
+  /***         plan on calling it, and to call it the linkage  */
+  /***         section should be combined.                     */
+  /*** Output: targete, code                           */
+  /***                                                 */
+  /*** ****************************************************************/
+
+  call_info.type = Make_entry;
+
+  /* preset the returned entry */
+
+  addr (a_targete) -> based_entry.code_ptr = null;
+  addr (a_targete) -> based_entry.env_ptr = null;
+
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+\f
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+
+
+make_join:
+
+  /* meter and trace the make_ptr/make_entry call */
+
+  call usage_values (call_info.start.pf, call_info.start.time);
+  call page$enter_data (baseptr (0), linkage_fault_start);
+
+  /* clear out the metering information */
+
+  call_info.search.time = 0;
+  call_info.search.pf = 0;
+  call_info.get_linkage.time = 0;
+  call_info.get_linkage.pf = 0;
+  call_info.def_search.time = 0;
+  call_info.def_search.pf = 0;
+
+  /* set up the common call_info stuff */
+
+  call_infop = addr (call_info);
+  call_info.codep = addr (a_code);
+  call_info.mcp, mcp = null;
+  call_info.save_ring = -1;
+
+  /* copy the args into automatic storage */
+
+  refp = a_refp;
+  seg_name = a_seg_name;
+  offset_name = a_offset_name;
+
+  /* preset the return code */
+
+  a_code = 0;
+
+  /* try to determine whether the ref pointer refers to an MSF */
+
+  if refp = null
+    then MSF_sw = false;
+    else do;
+      call link_man$own_linkage (ptr (refp, 0), linkp, null, null, code);
+      if code ^= 0
+        then MSF_sw = false;
+      else if addr (linkp -> linkage_header.def_ptr) -> its.its_mod ^= 
+             ITS_MODIFIER
+        then MSF_sw = false;
+      else do;
+        defp = linkp -> linkage_header.def_ptr;
+        if defp -> definition_header.msf_map_relp ^= None
+       then MSF_sw = true;
+       else MSF_sw = false;
+      end;
+    end;
+
+  /* search for the segment */
+
+  call fs_search (refp, seg_name, MSF_sw, segp, code);
+  if code ^= 0
+    then call exit (call_infop, code, null);
+
+  /* set up to handle connection failure gracefully */
+
+  call condition_ ("seg_fault_error", connect_fail_handler_);
+
+  nchars = length (rtrim (offset_name));
+
+  if nchars = 0
+    then do;
+
+      /* no offsetname, so just meter, finish tracing and return */
+
+      if call_info.type = Make_ptr
+        then call meter (call_infop, (LINK_REFNAME_BASE));
+        else do;
+
+       /* if we are returning an entry, we must combine the    */
+       /* target linkage section first.  If we combine the linkage     */
+       /* section we should run any first reference traps.     */
+
+       call combine_linkage (call_infop, segp, (null), target_linkagep,
+            (null), (null));
+       call meter (call_infop, (LINK_REFNAME_BASE));
+       call trap (call_infop, target_linkagep, segp);
+        end;
+      call exit (call_infop, 0, segp);
+    end;
+
+  /* set up the segname/offsetname pointers */
+
+  segnamep = addr (automatic_segname);
+  offsetnamep = addr (automatic_offsetname);
+
+  /* clear them out */
+
+  unspec (automatic_segname) = ""b;
+  unspec (automatic_offsetname) = ""b;
+
+  /* save the passed segname/offsetname values */
+
+  automatic_segname.count = length (rtrim (seg_name));
+  substr (automatic_segname.string, 1, automatic_segname.count) =
+       substr (seg_name, 1, automatic_segname.count);
+
+  automatic_offsetname.count = length (rtrim (offset_name));
+  substr (automatic_offsetname.string, 1, automatic_offsetname.count) =
+       substr (offset_name, 1, automatic_offsetname.count);
+
+  /* if the offsetname and segname are the same, we want       */
+  /* get_definition to retry using the offsetname "main_"      */
+  /* if this attempt fails                             */
+
+  if seg_name = offset_name
+    then retry_sw = Will_retry;
+    else retry_sw = No_retry;
+
+  call get_definition (call_infop, segnamep, offsetnamep, segp, retry_sw,
+       target_linkagep, targetp);
+
+  call meter (call_infop, (LINK_REFNAME_OFFSETNAME));
+  call trap (call_infop, target_linkagep, targetp);
+  call exit (call_infop, 0, targetp);
+
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+\f
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+
+
+convert_trap_link:
+  proc (infop,                 /** call info pointer   (in )   */
+       linkp,                  /** linkage pointer         (in )       */
+       defp,                   /** definition pointer  (in ) */
+       type_prp,                       /** type_pair pointer   (in ) */
+       offset_name,                    /** entrypoint name         (out) */
+       init_infop,                     /** init_info pointer   (out) */
+       star_system_sw);                /** *system or mapped   (out) */
+
+  /*** ****************************************************************/
+  /***                                                 */
+  /*** Name:   convert_trap_link                               */
+  /*** Input:  infop, linkp, defp, type_prp                    */
+  /*** Function:       determines whether the link in question has a   */
+  /***         trap_relp value.  If it does, then the link is  */
+  /***         a probably a *system link (type-5, class-5) or  */
+  /***         should should be treated as one.  If it is not  */
+  /***         not a *system link, and should be, we determine */
+  /***         what the offset_name to be found is and what the        */
+  /***         init_info pointer should be and then set the flag       */
+  /***         to indicate that this is to be snapped as a     */
+  /***         *system link.                           */
+  /*** Output: offset_name, init_infop, star_system_sw         */
+  /***                                                 */
+  /*** ****************************************************************/
+
+  /* parameters */
+
+  dcl infop            ptr parameter;
+  dcl linkp            ptr parameter;
+  dcl defp             ptr parameter;
+  dcl type_prp         ptr parameter;
+  dcl offset_name              char (256) parameter;
+  dcl init_infop               ptr parameter;
+  dcl star_system_sw   bit (1) parameter;
+
+  /* based */
+
+  dcl based_ptr                ptr based;
+  dcl 01 offsetname            aligned based (offsetnamep),
+       02 count                fixed bin (9) unsigned unaligned,
+       02 string               char (offsetname.count) unaligned;
+  dcl 01 segname               aligned based (segnamep),
+       02 count                fixed bin (9) unsigned unaligned,
+       02 string               char (segname.count) unaligned;
+  dcl 01 trap          aligned like link_trap_pair based (trapp);
+  dcl 01 type_pr               aligned like type_pair based (type_prp);
+
+  /* automatic */
+
+  dcl code             fixed bin (35) automatic;
+  dcl init_linkp               ptr automatic;
+  dcl offsetnamep              ptr automatic;
+  dcl segnamep         ptr automatic;
+  dcl trapp            ptr automatic;
+
+  segnamep = addrel (defp, type_pr.segname_relp);
+  offsetnamep = addrel (defp, type_pr.offsetname_relp);
+
+  /* preset output variables */
+
+  star_system_sw = false;
+  offset_name = offsetname.string;
+  if type_pr.trap_relp = None
+    then init_infop = null;
+    else init_infop = addrel (defp, type_pr.trap_relp);
+
+  /* first see if it is actually a *system link */
+
+  if type_pr.type = LINK_SELF_OFFSETNAME & type_pr.segname_relp = CLASS_SYSTEM
+    then do;
+      star_system_sw = true;
+      return;
+    end;
+
+  /* now check the conditions for converting a type 6 link */
+
+  if type_pr.type = LINK_CREATE_IF_NOT_FOUND
+    then do;
+
+      /* check for pl1 ext static */
+
+      if segname.string = "stat_"
+        then do;
+       star_system_sw = true;
+       return;
+        end;
+
+      /* check for fortran common blocks */
+
+      if offsetname.count = 0
+        then if index (segname.string, ".com") = segname.count - 3
+            then do;
+              star_system_sw = true;
+              offset_name = substr (segname.string, 1, segname.count - 4);
+              if offset_name = "b_"    /* blank common */
+                then offset_name = "blnk*com";
+              return;
+            end;
+            else ;
+
+      /* check for cobol FSB link */
+
+      else if segname.string = "cobol_fsb_"
+        then do;
+       offset_name = "cobol_fsb_" || offsetname.string;
+       star_system_sw = true;
+       return;
+        end;
+    end;
+
+  if type_pr.type = LINK_REFNAME_OFFSETNAME & type_pr.trap_relp ^= None
+    then do;
+
+      /* if we have a type 4 link with a trap-before link to datmk_    */
+      /* we force-snap the info-link of the trap, use that as the      */
+      /* init_info pointer and use the offsetname from the original    */
+      /* link as the name and then treat as a *system link.            */
+
+      trapp = addrel (defp, type_pr.trap_relp);
+      if segname.string = "stat_"
+        then if addrel (defp,
+               addrel (defp,
+               addrel (defp, addrel (linkp, trap.call_relp)
+               -> object_link.expression_relp)
+               -> exp_word.type_relp)
+               -> type_pair.segname_relp) -> acc_string.string = "datmk_"
+            then do;
+              init_linkp = addrel (linkp, trap.info_relp);
+
+              /* snap the info link */
+
+              call link_force (init_linkp, 0, code);
+              if code ^= 0
+                then call exit (call_infop, code, null);
+
+              init_infop = init_linkp -> based_ptr;
+              star_system_sw = true;
+            end;
+    end;
+
+  end convert_trap_link;
+
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+\f
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+
+
+star_system:
+  proc (infop,                 /** call_info pointer   (in )   */
+       link_pairp,                     /** pointer to link         (in ) */
+       defp,                   /** definition pointer  (in ) */
+       linkp,                  /** linkage pointer         (in ) */
+       type_prp,                       /** type_pair pointer   (in ) */
+       offset_name,                    /** ext var name string (in ) */
+       init_infop,                     /** init_info pointer   (in ) */
+       targetp);                       /** target variable         (out) */
+
+  /*** ****************************************************************/
+  /***                                                 */
+  /*** Name:   star_system                             */
+  /*** Input:  infop, link_pairp, defp, linkp, type_prp,       */
+  /***         offset_name, init_infop                 */
+  /*** Function:       determines the target of a *system link.  This  */
+  /***         procedure calls set_ext_variable_ to return the */
+  /***         variable_node which defines the named external  */
+  /***         variable, and then returns a pointer to the var */
+  /***         itself.                                 */
+  /*** Output: targetp                                 */
+  /***                                                 */
+  /*** ****************************************************************/
+
+  /* parameters */
+
+  dcl infop            ptr parameter;
+  dcl link_pairp               ptr parameter;
+  dcl defp             ptr parameter;
+  dcl linkp            ptr parameter;
+  dcl type_prp         ptr parameter;
+  dcl offset_name              char (256) parameter;
+  dcl init_infop               ptr parameter;
+  dcl targetp          ptr parameter;
+
+  /* based */
+
+  dcl 01 info          aligned like call_info based (infop);
+
+  /* automatic */
+
+  dcl code             fixed bin (35) automatic;
+  dcl sb                       ptr automatic;
+
+  /* set the stack base pointer */
+
+  if info.mcp = null
+    then sb = pds$stacks (level$get ());
+    else sb = ptr (info.mcp -> mc.prs (6), 0);
+
+  /* check to see if this variable has a deferred initialization type  */
+
+  call deferred_init (infop, init_infop, linkp);
+
+  /* now call set_ext_variable_ to get the variable node.  Note that   */
+  /* this call may not return if the target is an uninitialized VLA,   */
+  /* since this requires a call to fortran_storage_manager_. We cant   */
+  /* call this in ring 0 so we trap out to the user ring to call out   */
+  /* to set up the VLA.  The fortran_storage_manager_ is responsible   */
+  /* for completing the link snap.                             */
+
+  call set_ext_variable_$for_linker (offset_name, init_infop, sb,
+       ptr (init_infop, 0), ("0"b), targetp, code, info.mcp, def_ptr,
+       type_prp, link_pairp);
+  if code ^= 0
+    then call exit (infop, code, null);
+
+  /* get a pointer to the actual variable instead of the node */
+
+  targetp = targetp -> variable_node.vbl_ptr;
+
+  end star_system;
+
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+\f
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+
+
+star_heap:
+  proc (infop,                 /** call_info pointer   (in )   */
+       defp,                   /** def section ptr         (in ) */
+       linkp,                  /** linkage section ptr (in ) */
+       type_prp,                       /** type_pair pointer   (in ) */
+       targetp);                       /** target pointer          (out) */
+
+  /*** ****************************************************************/
+  /***                                                 */
+  /*** Name:   star_heap                                       */
+  /*** Input:  infop, defp, linkp, type_prp                    */
+  /*** Function:       given a pointer to the type_pair and definition */
+  /***         section for a link, get the offsetname and init */
+  /***         info pointer and call set_ext_variable_$star_heap       */
+  /***         to find or create the variable.         */
+  /*** Output: targetp                                 */
+  /***                                                 */
+  /*** ****************************************************************/
+
+  /* parameters */
+
+  dcl infop            ptr parameter;
+  dcl defp             ptr parameter;
+  dcl linkp            ptr parameter;
+  dcl type_prp         ptr parameter;
+  dcl targetp          ptr parameter;
+
+  /* based */
+
+  dcl 01 info          aligned like call_info based (infop);
+  dcl 01 offsetname            aligned based (offsetnamep),
+       02 count                fixed bin (9) unsigned unaligned,
+       02 string               char (offsetname.count) unaligned;
+  dcl 01 type_pr               aligned like type_pair based (type_prp);
+
+  /* automatic */
+
+  dcl init_infop               ptr automatic;
+  dcl offsetnamep              ptr automatic;
+  dcl sb                       ptr automatic;
+  dcl offset_name              char (256) automatic;
+
+  /* extract the variable name and init_info pointer */
+
+  offsetnamep = addrel (defp, type_pr.offsetname_relp);
+  offset_name = offsetname.string;
+
+  if type_pr.trap_relp = None
+    then init_infop = null;
+    else init_infop = addrel (defp, type_pr.trap_relp);
+
+  /* get the stack base pointer */
+
+  if info.mcp = null
+    then sb = pds$stacks (level$get ());
+    else sb = ptr (info.mcp -> mc.prs (6), 0);
+
+  /* get new init_info pointer if initialization type = INIT_DEFERRED */
+
+  call deferred_init (infop, init_infop, linkp);
+
+  /* call set_ext_variable_$star_heap to allocate the variable and     */
+  /* return a node ptr                                 */
+
+  call set_ext_variable_$star_heap (offset_name, init_infop, sb,
+       ptr (init_infop, 0), ("0"b), targetp, code);
+  if code ^= 0
+    then call exit (infop, code, null);
+
+  /* set the target to point to the variable itself */
+
+  targetp = targetp -> variable_node.vbl_ptr;
+
+  end star_heap;
+
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+\f
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+
+
+deferred_init:
+  proc (infop,                 /** call_info pointer   (in )   */
+       init_infop,                     /** init_info pointer   (i/o) */
+       linkp);                 /** linkage section ptr (in ) */
+
+  /*** ****************************************************************/
+  /***                                                 */
+  /*** Name:   deferred_init                           */
+  /*** Input:  infop, init_infop, linkp                        */
+  /*** Function:       locates the initialization info for deferred init       */
+  /***         external or heap initialization.  The procedure */
+  /***         for deferred initialization is as follows:      */
+  /***           - check to see if the init type is deferred.  */
+  /***           - if so, extract the target_relp and link_relp        */
+  /***             from the init_info.                 */
+  /***           - make sure the link referenced by target_relp        */
+  /***             has been snapped.                   */
+  /***           - chase the link to find the target segments  */
+  /***             linkage header.                             */
+  /***           - extract the def_ptr and original_linkage_ptr        */
+  /***             from the linkage_header.                    */
+  /***           - apply the link_relp to the original_linkage */
+  /***             pointer to find the unsnapped link.         */
+  /***           - extract a pointer to the init_info from the */
+  /***             def_ptr and type_pair.                      */
+  /***           - return the actual init_info pointer.        */
+  /*** Output: init_infop                              */
+  /***                                                 */
+  /*** ****************************************************************/
+
+  /* parameters */
+
+  dcl infop            ptr parameter;
+  dcl init_infop               ptr parameter;
+  dcl linkp            ptr parameter;
+
+  /* based */
+
+  dcl 01 lh            aligned like linkage_header based (lhp);
+  dcl based_ptr                ptr based;
+  dcl 01 type_pr               aligned like type_pair based (type_prp);
+  dcl 01 expr          aligned like exp_word based (exprp);
+  dcl 01 link_pair             aligned like object_link based (link_pairp);
+  dcl 01 init_info             aligned like link_init_deferred
+                       based (init_infop);
+
+  /* automatic */
+
+  dcl target_ptr_ptr   ptr automatic;
+  dcl lhp                      ptr automatic;
+  dcl exprp            ptr automatic;
+  dcl type_prp         ptr automatic;
+  dcl link_pairp               ptr automatic;
+
+  /* if no init_info, or init_info is not deferred, just return */
+
+  if init_infop = null
+    then return;
+
+  if init_info.header.type ^= INIT_DEFERRED
+    then return;
+
+  /* get the target partial link and make sure it is snapped */
+
+  target_ptr_ptr = addrel (linkp, init_info.target_relp);
+  if target_ptr_ptr -> its.its_mod ^= ITS_MODIFIER
+    then call exit (infop, error_table_$bad_deferred_init, null);
+
+  /* make sure the target of the link looks somewhat like a linkage    */
+  /* header and that the definition pointer is a pointer               */
+
+  lhp = target_ptr_ptr -> based_ptr;
+  if addr (lh.def_ptr) -> its.its_mod ^= ITS_MODIFIER
+    then call exit (infop, error_table_$no_defs, null);
+    else defp = lh.def_ptr;
+
+  /* get a pointer to the link specified in the original linkage       */
+  /* section and make sure it looks like an unsnapped link.            */
+
+  link_pairp = addrel (lh.original_linkage_ptr, init_info.link_relp);
+  if link_pair.tag ^= FAULT_TAG_2
+    then call exit (infop, error_table_$bad_deferred_init, null);
+
+  /* now decode the link and get a pointer to the init_info */
+
+  exprp = addrel (defp, link_pair.expression_relp);
+  type_prp = addrel (defp, expr.type_relp);
+  if type_pr.trap_relp = None
+    then init_infop = null;
+    else init_infop = addrel (defp, type_pr.trap_relp);
+
+  end deferred_init;
+
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+\f
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+
+
+self_reference:
+  proc (infop,                 /** call_info pointer   (in )   */
+       class,                  /** link class      (in ) */
+       textp,                  /** segment pointer         (in ) */
+       targetp);                       /** section pointer         (out) */
+
+  /*** ****************************************************************/
+  /***                                                 */
+  /*** Name:   self_reference                          */
+  /*** Input:  infop, class, textp                             */
+  /*** Function:       given a link class and a pointer to the owners  */
+  /***         text_section, get the other section pointers and        */
+  /***         return a pointer to the section specified by the        */
+  /***         class of the link.                              */
+  /*** Output: targetp                                 */
+  /***                                                 */
+  /*** ****************************************************************/
+
+  /* parameters */
+
+  dcl infop            ptr parameter;
+  dcl class            fixed bin (18) unsigned parameter;
+  dcl textp            ptr parameter;
+  dcl targetp          ptr parameter;
+
+  /* automatic */
+
+  dcl code             fixed bin (35) automatic;
+  dcl linkp            ptr automatic;
+  dcl staticp          ptr automatic;
+  dcl symbolp          ptr automatic;
+
+  /* get pointers to the various sections */
+
+  call link_man$own_linkage (textp, linkp, staticp, symbolp, code);
+  if code ^= 0
+    then call exit (infop, code, null);
+
+  /* return the section pointer based on the link class */
+
+  if /* case */ class = CLASS_TEXT
+    then targetp = textp;
+  else if class = CLASS_LINKAGE
+    then targetp = linkp;
+  else if class = CLASS_STATIC
+    then targetp = staticp;
+  else if class = CLASS_SYMBOL
+    then targetp = symbolp;
+  else call exit (infop, error_table_$bad_self_ref, null);
+
+  end self_reference;
+
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+\f
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+
+
+search_for_segment:
+  proc (infop,                 /** call_info pointer   (in )   */
+       segnamep,                       /** segname acc pointer (in ) */
+       refp,                   /** referencing pointer (in ) */
+       MSF_sw,                 /** is caller an MSF    (in ) */
+       segp,                   /** found segment ptr   (out) */
+       code);                  /** error code      (out) */
+
+  /*** ****************************************************************/
+  /***                                                 */
+  /*** Name:   search_for_segment                              */
+  /*** Input:  infop, segnamep, refp                   */
+  /*** Function:       calls fs_search to search for the refname given */
+  /***         by the acc_string pointer to by segnamep, and   */
+  /***         meters the call.                                */
+  /*** Output: segp, code                              */
+  /***                                                 */
+  /*** ****************************************************************/
+
+  /* parameters */
+
+  dcl infop            ptr parameter;
+  dcl segnamep         ptr parameter;
+  dcl refp             ptr parameter;
+  dcl MSF_sw           bit (1) aligned parameter;
+  dcl segp             ptr parameter;
+  dcl code             fixed bin (35) parameter;
+
+  /* based */
+
+  dcl 01 info          aligned like call_info based (infop);
+  dcl 01 segname               aligned based (segnamep),
+       02 count                fixed bin (9) unsigned unaligned,
+       02 string               char (segname.count) unaligned;
+
+  /* automatic */
+
+  dcl 01 finish                aligned like usage automatic;
+  dcl 01 start         aligned like usage automatic;
+
+  /* do the search and meter the time an pagewaits */
+
+  call usage_values (start.pf, start.time);
+
+  call fs_search (refp, segname.string, MSF_sw, segp, code);
+
+  call usage_values (finish.pf, finish.time);
+
+  /* calculate the metering info and add it to the search metering */
+
+  info.search.pf = info.search.pf + (finish.pf - start.pf);
+  info.search.time = info.search.time + (finish.time - start.time);
+
+  end search_for_segment;
+
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+\f
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+
+
+get_offsetnamep:
+  proc (infop,                 /** call_info pointer   (in )   */
+       defp,                   /** definition pointer  (in ) */
+       type_prp,                       /** type_pair pointer   (in ) */
+       offsetnamep);           /** offsetname pointer (out) */
+
+  /*** ****************************************************************/
+  /***                                                 */
+  /*** Name:   get_offsetnamep                         */
+  /*** Input:  infop, defp, type_prp                   */
+  /*** Function:       extract a pointer to the offsetname for the link        */
+  /***         from the type_pair.  If there is no offsetname  */
+  /***         or the type is 6 and the offset name length is 0,       */
+  /***         the null pointer is returned.                   */
+  /*** Output: offsetnamep                             */
+  /***                                                 */
+  /*** ****************************************************************/
+
+  /* parameters */
+
+  dcl infop            ptr parameter;
+  dcl defp             ptr parameter;
+  dcl type_prp         ptr parameter;
+  dcl offsetnamep              ptr parameter;
+
+  /* based */
+
+  dcl 01 offsetname            aligned based (offsetnamep),
+       02 count                fixed bin (9) unsigned unaligned,
+       02 string               char (offsetname.count) unaligned;
+  dcl 01 type_pr               aligned like type_pair based (type_prp);
+
+  if type_pr.offsetname_relp = None
+    then offsetnamep = null;
+    else do;
+
+      /* type-6 links use a valid acc_string with a zero length instead. */
+
+      offsetnamep = addrel (defp, type_pr.offsetname_relp);
+      if type_pr.type = LINK_CREATE_IF_NOT_FOUND & offsetname.count = 0
+        then offsetnamep = null;
+    end;
+
+  end get_offsetnamep;
+
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+\f
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+
+
+combine_linkage:
+  proc (infop,                 /** call_info pointer   (in )   */
+       segp,                   /** target segment ptr  (in ) */
+       textp,                  /** text section ptr    (out) */
+       linkp,                  /** linkage section ptr (out) */
+       statp,                  /** static section ptr  (out) */
+       symbp);                 /** symbol section ptr  (out) */
+
+  /*** ****************************************************************/
+  /***                                                 */
+  /*** Name:   combine_linkage                         */
+  /*** Input:  infop, segp                             */
+  /*** Function:       given a pointer to a segment (segp), combine the        */
+  /***         linkage section (if necessary) and return the   */
+  /***         pointers to the various sections.  This routine */
+  /***         also meters the call.                   */
+  /*** Output: textp, linkp, statp, symbp                      */
+  /***                                                 */
+  /*** ****************************************************************/
+
+  /* parameters */
+
+  dcl infop            ptr parameter;
+  dcl segp             ptr parameter;
+  dcl textp            ptr parameter;
+  dcl linkp            ptr parameter;
+  dcl statp            ptr parameter;
+  dcl symbp            ptr parameter;
+
+  /* based */
+
+  dcl 01 info          aligned like call_info based (infop);
+
+  /* automatic */
+
+  dcl 01 finish                aligned like usage automatic;
+  dcl 01 start         aligned like usage automatic;
+
+  /* combine the linkage section and meter the time and pagewaits */
+
+  call usage_values (start.pf, start.time);
+
+  textp = ptr (segp, 0);
+  call link_man$other_linkage (textp, linkp, statp, symbp, code);
+
+  call usage_values (finish.pf, finish.time);
+
+  /* add in to metering info */
+
+  info.get_linkage.pf = info.get_linkage.pf + (finish.pf - start.pf);
+  info.get_linkage.time = info.get_linkage.time + (finish.time - start.time);
+
+  if code ^= 0
+    then call exit (infop, code, null);
+
+  if linkp = null
+    then call exit (infop, error_table_$no_linkage, null);
+
+  end combine_linkage;
+
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+\f
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+
+
+get_definition:
+  proc (infop,                 /** call_info pointer   (in )   */
+       segnamep,                       /** segname acc ptr         (in ) */
+       offsetnamep,                    /** offsetname acc ptr  (in ) */
+       segp,                   /** segment to search   (in ) */
+       retry,                  /** will retry "main_"  (in ) */
+       target_linkagep,                /** linkp of target seg (out) */
+       targetp);                       /** target pointer          (out) */
+
+  /*** ****************************************************************/
+  /***                                                 */
+  /*** Name:   get_definition                          */
+  /*** Input:  infop, segnamep, offsetnamep, segp, retry       */
+  /*** Function:       combines the linkage section for the segment    */
+  /***         specified, and then searches the definition     */
+  /***         section for a definition matching the segname   */
+  /***         and offsetname given and meters the search.     */
+  /***         A pointer to the definition target is then      */
+  /***         generated based on the definition class, the    */
+  /***         section pointers returned by combining the      */
+  /***         linkage, and the definition offset.  If the     */
+  /***         search fails and the retry flag is set, we      */
+  /***         try another search for the entrypoint "main_".  */
+  /*** Output: targetp                                 */
+  /***                                                 */
+  /*** ****************************************************************/
+
+  /* constant */
+
+  dcl 01 main_acc              aligned static options (constant),
+       02 count                fixed bin (9) unsigned unaligned init (5),
+       02 string               char (5) unaligned init ("main_");
+
+  /* parameters */
+
+  dcl infop            ptr parameter;
+  dcl segnamep         ptr parameter;
+  dcl offsetnamep              ptr parameter;
+  dcl retry            bit (1) parameter;
+  dcl target_linkagep  ptr parameter;
+  dcl segp             ptr parameter;
+  dcl targetp          ptr parameter;
+
+  /* based */
+
+  dcl based_ptr                ptr based;
+  dcl 01 def           aligned like definition based (defp);
+  dcl 01 info          aligned like call_info based (infop);
+
+  /* automatic */
+
+  dcl code             fixed bin (35) automatic;
+  dcl defp             ptr automatic;
+  dcl 01 finish                aligned like usage automatic;
+  dcl linkp            ptr automatic;
+  dcl 01 start         aligned like usage automatic;
+  dcl statp            ptr automatic;
+  dcl symbp            ptr automatic;
+  dcl textp            ptr automatic;
+
+  /* if we have no name to search for, don't bother trying */
+
+  if offsetnamep = null
+    then return;
+
+  /* combine the linkage section and get the section pointers */
+
+  call combine_linkage (infop, segp, textp, linkp, statp, symbp);
+
+  /* save the linkage pointer in case we have first reference traps to run */
+
+  target_linkagep = linkp;
+
+  call usage_values (start.pf, start.time);
+  call get_defptr_ (linkp -> linkage_header.def_ptr, segnamep, offsetnamep,
+       defp, code);
+  call usage_values (finish.pf, finish.time);
+
+  /* update the metering info */
+
+  info.def_search.pf = info.def_search.pf + (finish.pf - start.pf);
+  info.def_search.time = info.def_search.time + (finish.time - start.time);
+
+  if retry & code = error_table_$no_ext_sym
+    then do;
+
+      /* retry the search with an offsetname of "main_" */
+
+      call usage_values (start.pf, start.time);
+      call get_defptr_ (linkp -> linkage_header.def_ptr, segnamep,
+        addr (main_acc), defp, code);
+      call usage_values (finish.pf, finish.time);
+
+      /* add to the metering info */
+
+      info.def_search.pf = info.def_search.pf + (finish.pf - start.pf);
+      info.def_search.time = info.def_search.time + (finish.time - start.time);
+
+    end;
+
+  if code ^= 0
+    then call exit (infop, code, null);
+
+  /* check for an indirect definition */
+
+  if def.indirect
+    then do;
+
+      /* an indirect definition (used only in component 0 of an        */
+      /* object MSF) is used to refer to something in another  */
+      /* component by adding another indirection through a partial     */
+      /* link. In this case the thing_relp is the offset in the        */
+      /* linkage section of a partial link to the actual definition    */
+      /* target.  In some cases this link will have been snapped       */
+      /* already by the msf_prelink_ first reference trap, if not, we  */
+      /* snap the link, and then use the indirection to give us our    */
+      /* definition target.                                    */
+
+      if def.class ^= CLASS_LINKAGE
+        then call exit (infop, error_table_$bad_indirect_def, null);
+
+      /* if the link is snapped, just get the value and return */
+
+      targetp = addrel (linkp, def.thing_relp);
+      if targetp -> its.its_mod = ITS_MODIFIER
+        then do;
+       targetp = targetp -> based_ptr;
+       return;
+        end;
+
+      /* if not make sure it is a partial link */
+
+      if targetp -> its.its_mod ^= FAULT_TAG_3
+        then call exit (infop, error_table_$bad_indirect_def, null);
+
+      /* then snap it, get the value and return */
+
+      call snap_partial_link (infop, targetp, textp);
+      targetp = targetp -> based_ptr;
+      return;
+    end;
+
+  /* calculate the target based on the definition class and offset */
+
+  if /* case */ def.class = CLASS_TEXT
+    then targetp = addrel (textp, def.thing_relp);
+  else if def.class = CLASS_LINKAGE
+    then targetp = addrel (linkp, def.thing_relp);
+  else if def.class = CLASS_STATIC
+    then targetp = addrel (statp, def.thing_relp);
+  else if def.class = CLASS_SYMBOL
+    then targetp = addrel (symbp, def.thing_relp);
+  else call exit (infop, error_table_$bad_class_def, null);
+
+  end get_definition;
+
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+\f
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+
+
+snap_partial_link:
+  proc (infop,                 /** call_info pointer   (in )   */
+       link_pairp,                     /** link pair to snap   (i/o) */
+       refp);                  /** ref ptr for search  (in ) */
+
+  /*** ****************************************************************/
+  /***                                                 */
+  /*** Name:   snap_partial_link                               */
+  /*** Input:  infop, link_pairp, refp                 */
+  /*** Function:       snaps a partial link to another component in    */
+  /***         the same directory.                             */
+  /*** Output: link_pairp                              */
+  /***                                                 */
+  /*** ****************************************************************/
+
+  /* parameters */
+
+  dcl infop            ptr parameter;
+  dcl link_pairp               ptr parameter;
+  dcl refp             ptr parameter;
+
+  /* based */
+
+  dcl based_ptr                ptr based;
+  dcl 01 info          aligned like call_info based (infop);
+  dcl 01 link_pair             aligned like partial_link based (link_pairp);
+
+  /* automatic */
+
+  dcl 01 finish                aligned like usage automatic;
+  dcl linkp            ptr automatic;
+  dcl refname          char (32) automatic;
+  dcl 01 start         aligned like usage automatic;
+  dcl statp            ptr automatic;
+  dcl symbp            ptr automatic;
+  dcl textp            ptr automatic;
+
+  /* get the name of the other component */
+
+  refname = ltrim (char (link_pair.component));
+
+  /* perform the search and meter the time and pagewaits */
+
+  call usage_values (start.pf, start.time);
+  call fs_search$same_directory (refp, refname, segp, code);
+  call usage_values (finish.pf, finish.time);
+
+  /* update the metering info */
+
+  info.search.pf = info.search.pf + (finish.pf - start.pf);
+  info.search.time = info.search.time + (finish.time - start.time);
+
+  /* if we didn't find it, something is broken . . . */
+
+  if code ^= 0
+    then call exit (infop, code, null);
+
+  /* combine the target linkage section */
+
+  call combine_linkage (infop, segp, textp, linkp, statp, symbp);
+
+  /* now snap the link based on the type and offset in the link */
+
+  if /* case */ link_pair.type = CLASS_TEXT
+    then link_pairp -> based_ptr = addrel (textp, link_pair.offset);
+  else if link_pair.type = CLASS_LINKAGE
+    then link_pairp -> based_ptr = addrel (linkp, link_pair.offset);
+  else if link_pair.type = CLASS_STATIC
+    then link_pairp -> based_ptr = addrel (statp, link_pair.offset);
+  else if link_pair.type = CLASS_SYMBOL
+    then link_pairp -> based_ptr = addrel (symbp, link_pair.offset);
+  else call exit (infop, error_table_$bad_indirect_def, null);
+
+  end snap_partial_link;
+
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+\f
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+
+
+snap:
+  proc (targetp,                       /** value to snap to    (in )   */
+       expression,                     /** offset to add           (in ) */
+       link_pairp);                    /** link pair to snap   (i/o) */
+
+  /*** ****************************************************************/
+  /***                                                 */
+  /*** Name:   snap                                    */
+  /*** Input:  targetp, expression, link_pairp         */
+  /*** Function:       completes the snapping of the link and sets     */
+  /***         targetp to point to the same value as the snapped       */
+  /***         link;                                   */
+  /*** Output: targetp, link_pairp                             */
+  /***                                                 */
+  /*** ****************************************************************/
+
+  /* parameters */
+
+  dcl targetp          ptr parameter;
+  dcl expression               fixed bin (17) parameter;
+  dcl link_pairp               ptr parameter;
+
+  /* based */
+
+  dcl 01 link_as_its   aligned like its based (link_pairp);
+  dcl 01 link_pair             aligned like object_link based (link_pairp);
+  dcl link_ptr         ptr based (link_pairp);
+
+  /* automatic */
+
+  dcl modifier         bit (6) automatic;
+  dcl sb                       ptr automatic;
+
+  /* add in the expression value */
+
+  targetp = addrel (targetp, expression);
+
+  /* get the original modifier from the link */
+
+  modifier = link_pair.modifier;
+
+  /* store the new pointer back into the link */
+
+  link_ptr = targetp;
+
+  /* put the link modifier back in */
+
+  link_as_its.mod = modifier;
+
+  /* put the run-depth into the pointer */
+
+  sb = pds$stacks (level$get ());
+  link_pair.run_depth = sb -> stack_header.run_unit_depth;
+
+  end snap;
+
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+\f
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+
+
+meter:
+  proc (infop,                 /** call_info pointer   (in )   */
+       type);                  /** link type       (in ) */
+
+  /*** ****************************************************************/
+  /***                                                 */
+  /*** Name:   meter                                   */
+  /*** Input:  infop, type                             */
+  /*** Function:       given the call_info structure containing the    */
+  /***         metering info for the last call, and the type of        */
+  /***         link snapped, update the perprocess link meters */
+  /***         in pds and the system_wide meters in ahd.       */
+  /*** Output: none                                    */
+  /***                                                 */
+  /*** ****************************************************************/
+
+  /* parameters */
+
+  dcl infop            ptr parameter;
+  dcl type             fixed bin (18) unsigned parameter;
+
+  /* based */
+
+  dcl 01 info          aligned like call_info based (infop);
+  dcl 01 lm            aligned like link_meters based (lmp);
+
+  /* automatic */
+
+  dcl elapsed_time             fixed bin (35) automatic;
+  dcl elapsed_pf               fixed bin (30) automatic;
+  dcl bin_no           fixed bin automatic;
+  dcl lmp                      ptr automatic;
+
+  /* get the final metering values */
+
+  call usage_values (info.finish.pf, info.finish.time);
+
+  /* calculate the elapsed time and pagewaits */
+
+  elapsed_time = bin (info.finish.time - info.start.time, 35);
+  elapsed_pf = bin (info.finish.pf - info.start.pf, 30);
+
+  /* determine which bin this fault goes into */
+
+  bin_no = max (1, min (4, divide (elapsed_time, 25000, 17, 0) + 1));
+
+  /* update the counts in pds */
+
+  pds$link_meters_bins (bin_no) = pds$link_meters_bins (bin_no) + 1;
+  pds$link_meters_pgwaits (bin_no) = pds$link_meters_pgwaits (bin_no) +
+       elapsed_pf;
+  pds$link_meters_times (bin_no) = pds$link_meters_times (bin_no) +
+       elapsed_time;
+
+  /* update the ahd link meters */
+
+  lmp = addr (ahd$link_meters (bin_no));
+
+  lm.total = lm.total + 1;
+  lm.pf = lm.pf + elapsed_pf;
+  lm.time = lm.time + elapsed_time;
+
+  if /* case */ (info.type = Link_fault | info.type = Link_force) &
+       (type = LINK_REFNAME_BASE | type = LINK_REFNAME_OFFSETNAME)
+    then do;
+      lm.search_pf = lm.search_pf + info.search.pf;
+      lm.search_time = lm.search_time + info.search.time;
+      lm.get_linkage_pf = lm.get_linkage_pf + info.get_linkage.pf;
+      lm.get_linkage_time = lm.get_linkage_time + info.get_linkage.time;
+      lm.defsearch_pf = lm.defsearch_pf + info.def_search.pf;
+      lm.defsearch_time = lm.defsearch_time + info.def_search.time;
+    end;
+  else if type = LINK_CREATE_IF_NOT_FOUND
+    then do;
+      lm.total_type_6 = lm.total_type_6 + 1;
+      lm.type_6_pf = lm.type_6_pf + elapsed_pf;
+      lm.type_6_time = lm.type_6_time + elapsed_time;
+    end;
+  else do;
+    if info.type = Make_entry | info.type = Make_ptr
+      then lm.tot_make_ptr = lm.tot_make_ptr + 1;
+    lm.total_others = lm.total_others + 1;
+    lm.others_pf = lm.others_pf + elapsed_pf;
+    lm.others_time = lm.others_time + elapsed_time;
+  end;
+
+  end meter;
+
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+\f
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+
+
+trap:
+  proc (infop,                 /** call_info pointer   (in )   */
+       target_linkagep,                /** target linkage scn  (in ) */
+       targetp);                       /** return value            (in ) */
+
+  /*** ****************************************************************/
+  /***                                                 */
+  /*** Name:   trap                                    */
+  /*** Input:  infop, target_linkagep, targetp         */
+  /*** Function:       executes first reference traps in the target of */
+  /***         the link snapped.  Since this operation involves        */
+  /***         calling back out to the user ring, we set fix up        */
+  /***         the maching conditions, error codes, and return */
+  /***         values prior to calling trap_caller_caller_.    */
+  /***         If there are no traps, we return and exit through       */
+  /***         the normal mechanism.                   */
+  /*** Output: none                                    */
+  /***                                                 */
+  /*** ****************************************************************/
+
+  /* parameters */
+
+  dcl infop            ptr parameter;
+  dcl target_linkagep  ptr parameter;
+  dcl targetp          ptr parameter;
+
+  /* based */
+
+  dcl 01 info          aligned like call_info based (infop);
+
+  /* now we see if we have first reference traps to run in the target  */
+  /* of the link we just finished snapping.                    */
+
+  if target_linkagep ^= null
+    then do;
+      if target_linkagep -> virgin_linkage_header.first_ref_relp ^= None
+        then do;
+
+       /* we adjust the machine conditions now, since we won't */
+       /* return from trap_caller_caller_ . . .                */
+
+       call adjust_mc (mcp);
+
+       /* set the return values */
+
+       if info.type ^= Link_fault
+         then a_code = 0;
+
+       if /* case */ info.type = Make_ptr
+         then a_targetp = targetp;
+       else if info.type = Make_entry
+         then addr (a_targete) -> based_entry.code_ptr = targetp;
+
+       /* now we complete tracing of the fault, since the trap */
+       /* should not return.                           */
+
+       call page$enter_data ((targetp), linkage_fault_end);
+
+       /* trap back to the user ring and execute the firstref traps */
+
+       call trap_caller_caller_ (info.mcp, target_linkagep, null,
+            null, null, info.codep, code);
+
+       /* just in case we returned. . . */
+
+       if info.mcp ^= null
+         then call exit (infop, code, null);
+        end;
+
+    end;
+
+  end trap;
+
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+\f
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+
+
+adjust_mc:
+  proc (mcp);                  /** machine conditions  (in )   */
+
+  /*** ****************************************************************/
+  /***                                                 */
+  /*** Name:   adjust_mc                                       */
+  /*** Input:  mcp                                     */
+  /*** Function:       adjusts the fault machine conditions so that the        */
+  /***         fault can be restarted.                 */
+  /*** Output: none.                                   */
+  /***                                                 */
+  /*** ****************************************************************/
+
+  /* parameters */
+
+  dcl mcp                      ptr parameter;
+
+  /* based */
+
+  dcl 01 instr         aligned based (instrp),
+       02 address              bit (18) unaligned,
+       02 op_code              bit (12) unaligned,
+       02 modifier             bit (6) unaligned;
+
+  /* automatic */
+
+  dcl scup             ptr automatic;
+  dcl instrp           ptr automatic;
+
+  /* don't try fixing machine conditions that aren't there. . . */
+
+  if mcp = null
+    then return;
+
+  scup = addr (mcp -> mc.scu);
+  instrp = addr (scup -> scu.even_inst);
+  instr.address = scup -> scu.ca;
+  instr.modifier = indirect;
+
+  end adjust_mc;
+
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+\f
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+
+connect_fail_handler_:
+  proc (a_mcp,                 /** machine conditions  (in )   */
+       a_condition_name,               /** condition name          (in ) */
+       a_wcp,                  /** crawlout info           (in ) */
+       a_infop,                        /** condition info          (in ) */
+       a_continue_flag);               /** continue flag           (out) */
+
+  /*** ****************************************************************/
+  /***                                                 */
+  /*** Name:   connect_fail_handler_                   */
+  /*** Input:  mcp, condition_name, wcp, infop, continue_flag  */
+  /*** Function:       handles the seg_fault condition.  This handler  */
+  /***         in enabled prior to the definition search in    */
+  /***         type-4 and type-6 links.  When invoked, the     */
+  /***         faulting segment is compared with the global    */
+  /***         variable segp, it the segments are not the same,        */
+  /***         this means we have faulted somewhere unexpected,        */
+  /***         so we continue to signal.  If the fault occurred        */
+  /***         on the expected segment, we assume it is because        */
+  /***         of a connection failure and simply return abort */
+  /***         the link fault returning the appropriate code.  */
+  /***                                                 */
+  /***         NB.  Because of the machanism involved, this    */
+  /***              procedure assumes that the global variables        */
+  /***              segp and call_infop are set prior to the   */
+  /***              establishment of the condition handler.    */
+  /*** Output: none                                    */
+  /***                                                 */
+  /*** ****************************************************************/
+
+  /* parameters */
+
+  dcl a_mcp            ptr parameter;
+  dcl a_condition_name char (*) parameter;
+  dcl a_wcp            ptr parameter;
+  dcl a_infop          ptr parameter;
+  dcl a_continue_flag  bit (1) parameter;
+
+  /* automatic */
+
+  dcl faulted_segno            fixed bin (18) automatic;
+  dcl segno            fixed bin (18) automatic;
+  dcl scup             ptr automatic;
+
+  /* get the segment numbers of the faulting segment and the target    */
+  /* segment of the current link snapping operation            */
+
+  a_continue_flag = false;
+  scup = addr (a_mcp -> mc.scu);
+  faulted_segno = bin (scup -> scu.tpr.tsr, 18);
+  segno = bin (baseno (segp), 18);
+
+  /* if they are different, continue to signal */
+
+  if faulted_segno ^= segno
+    then do;
+      a_continue_flag = true;
+      return;
+    end;
+
+  /* otherwise assume a connection failure, and return the code */
+
+  connect_fail_code = a_mcp -> mc.errcode;
+
+  /* NB.  here we set a global code and do a non-local goto which      */
+  /*   then calls the exit procedure rather than calling exit  */
+  /*   directly in order to keep the exit and adjust_mc procedures     */
+  /*   as quick procedures.                            */
+
+  goto CONNECT_FAIL_EXIT;
+
+  end connect_fail_handler_;
+
+CONNECT_FAIL_EXIT:
+  call exit (call_infop, connect_fail_code, null);
+
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+\f
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+
+
+exit:
+  proc (infop,                 /** call_info pointer   (in )   */
+       code,                   /** code to return          (in ) */
+       targetp);                       /** target (for trace)  (in )   */
+
+  /*** ****************************************************************/
+  /***                                                 */
+  /*** Name:   exit                                    */
+  /*** Input:  info, code, targetp                             */
+  /*** Function:       returns from the fault or gate entry and cleans */
+  /***         up.  This procedure differs depending on where  */
+  /***         we entered from:                                */
+  /***           link_fault - save the code in the machine     */
+  /***                      conditions, adjust the machine     */
+  /***                      conditions to allow restart, reset */
+  /***                      the validation level back, */
+  /***                      complete the fault trace, and exit */
+  /***           link_force - set the code to be returned,     */
+  /***                      complete the fault trace, and exit */
+  /***           make_ptr   - set the return pointer and code, */
+  /***                      complete the fault trace, and exit */
+  /***           make_entry - set the return entry and code,   */
+  /***                      complete the fault trace, and exit */
+  /***                                                 */
+  /***         NB.  When completing the fault trace, the code to       */
+  /***              be returned is examined.  If it it nonzero,        */
+  /***              the info_ptr for the call to page$enter_data       */
+  /***              is 0|0.  If the code is zero, the targetp  */
+  /***              value is passed to page$enter_data.        */
+  /*** Output: none                                    */
+  /***                                                 */
+  /*** ****************************************************************/
+
+  /* parameters */
+
+  dcl infop            ptr parameter;
+  dcl code             fixed bin (35) parameter;
+  dcl targetp          ptr parameter;
+
+  /* based */
+
+  dcl 01 info          aligned like call_info based (infop);
+  dcl 01 exit_mc               aligned like mc based (info.mcp);
+
+  /* if we had a make_ptr or make_entry call, set the return value */
+
+  if /* case */ info.type = Make_ptr
+    then a_targetp = targetp;
+  else if info.type = Make_entry
+    then addr (a_targete) -> based_entry.code_ptr = targetp;
+
+  /* return the code */
+
+  if info.type = Link_fault
+    then do;
+      call level$set ((info.save_ring));
+      exit_mc.errcode = code;
+      call adjust_mc (info.mcp);
+    end;
+    else a_code = code;
+
+  /* complete fault tracing */
+
+  if code = 0
+    then call page$enter_data ((targetp), linkage_fault_end);
+    else call page$enter_data (baseptr (0), linkage_fault_end);
+
+  /* non-local goto to outer level and return */
+
+  goto EXIT;
+
+  end exit;
+
+EXIT:
+  return;
+
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+%page;
+/****  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */
+
+
+%include definition_dcls;
+%page;
+%include its;
+%page;
+%include link_meters;
+%page;
+%include mc;
+%page;
+%include object_link_dcls;
+%page;
+%include stack_header;
+%page;
+%include system_link_names;
+%page;
+%include trace_types;
+
+  end link_snap;