xref: /openbsd-src/gnu/lib/libiberty/src/alloca.c (revision 20fce977aadac3358da45d5027d7d19cdc03b0fe)
100bf4279Sespie /* alloca.c -- allocate automatically reclaimed memory
200bf4279Sespie    (Mostly) portable public-domain implementation -- D A Gwyn
300bf4279Sespie 
400bf4279Sespie    This implementation of the PWB library alloca function,
500bf4279Sespie    which is used to allocate space off the run-time stack so
600bf4279Sespie    that it is automatically reclaimed upon procedure exit,
700bf4279Sespie    was inspired by discussions with J. Q. Johnson of Cornell.
800bf4279Sespie    J.Otto Tennant <jot@cray.com> contributed the Cray support.
900bf4279Sespie 
1000bf4279Sespie    There are some preprocessor constants that can
1100bf4279Sespie    be defined when compiling for your specific system, for
1200bf4279Sespie    improved efficiency; however, the defaults should be okay.
1300bf4279Sespie 
1400bf4279Sespie    The general concept of this implementation is to keep
1500bf4279Sespie    track of all alloca-allocated blocks, and reclaim any
1600bf4279Sespie    that are found to be deeper in the stack than the current
1700bf4279Sespie    invocation.  This heuristic does not reclaim storage as
1800bf4279Sespie    soon as it becomes invalid, but it will do so eventually.
1900bf4279Sespie 
2000bf4279Sespie    As a special case, alloca(0) reclaims storage without
2100bf4279Sespie    allocating any.  It is a good idea to use alloca(0) in
2200bf4279Sespie    your main control loop, etc. to force garbage collection.  */
2300bf4279Sespie 
249588ddcfSespie /*
259588ddcfSespie 
269588ddcfSespie @deftypefn Replacement void* alloca (size_t @var{size})
279588ddcfSespie 
289588ddcfSespie This function allocates memory which will be automatically reclaimed
299588ddcfSespie after the procedure exits.  The @libib{} implementation does not free
309588ddcfSespie the memory immediately but will do so eventually during subsequent
319588ddcfSespie calls to this function.  Memory is allocated using @code{xmalloc} under
329588ddcfSespie normal circumstances.
339588ddcfSespie 
349588ddcfSespie The header file @file{alloca-conf.h} can be used in conjunction with the
359588ddcfSespie GNU Autoconf test @code{AC_FUNC_ALLOCA} to test for and properly make
369588ddcfSespie available this function.  The @code{AC_FUNC_ALLOCA} test requires that
379588ddcfSespie client code use a block of preprocessor code to be safe (see the Autoconf
389588ddcfSespie manual for more); this header incorporates that logic and more, including
399588ddcfSespie the possibility of a GCC built-in function.
409588ddcfSespie 
419588ddcfSespie @end deftypefn
429588ddcfSespie 
439588ddcfSespie */
449588ddcfSespie 
4500bf4279Sespie #ifdef HAVE_CONFIG_H
4600bf4279Sespie #include <config.h>
4700bf4279Sespie #endif
4800bf4279Sespie 
499588ddcfSespie #include <libiberty.h>
509588ddcfSespie 
5100bf4279Sespie #ifdef HAVE_STRING_H
5200bf4279Sespie #include <string.h>
5300bf4279Sespie #endif
5400bf4279Sespie #ifdef HAVE_STDLIB_H
5500bf4279Sespie #include <stdlib.h>
5600bf4279Sespie #endif
5700bf4279Sespie 
589588ddcfSespie /* These variables are used by the ASTRDUP implementation that relies
599588ddcfSespie    on C_alloca.  */
60*20fce977Smiod #ifdef __cplusplus
61*20fce977Smiod extern "C" {
62*20fce977Smiod #endif /* __cplusplus */
639588ddcfSespie const char *libiberty_optr;
649588ddcfSespie char *libiberty_nptr;
659588ddcfSespie unsigned long libiberty_len;
66*20fce977Smiod #ifdef __cplusplus
67*20fce977Smiod }
68*20fce977Smiod #endif /* __cplusplus */
6900bf4279Sespie 
7000bf4279Sespie /* If your stack is a linked list of frames, you have to
7100bf4279Sespie    provide an "address metric" ADDRESS_FUNCTION macro.  */
7200bf4279Sespie 
7300bf4279Sespie #if defined (CRAY) && defined (CRAY_STACKSEG_END)
749588ddcfSespie static long i00afunc ();
7500bf4279Sespie #define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg))
7600bf4279Sespie #else
7700bf4279Sespie #define ADDRESS_FUNCTION(arg) &(arg)
7800bf4279Sespie #endif
7900bf4279Sespie 
8000bf4279Sespie #ifndef NULL
8100bf4279Sespie #define	NULL	0
8200bf4279Sespie #endif
8300bf4279Sespie 
8400bf4279Sespie /* Define STACK_DIRECTION if you know the direction of stack
8500bf4279Sespie    growth for your system; otherwise it will be automatically
8600bf4279Sespie    deduced at run-time.
8700bf4279Sespie 
8800bf4279Sespie    STACK_DIRECTION > 0 => grows toward higher addresses
8900bf4279Sespie    STACK_DIRECTION < 0 => grows toward lower addresses
9000bf4279Sespie    STACK_DIRECTION = 0 => direction of growth unknown  */
9100bf4279Sespie 
9200bf4279Sespie #ifndef STACK_DIRECTION
9300bf4279Sespie #define	STACK_DIRECTION	0	/* Direction unknown.  */
9400bf4279Sespie #endif
9500bf4279Sespie 
9600bf4279Sespie #if STACK_DIRECTION != 0
9700bf4279Sespie 
9800bf4279Sespie #define	STACK_DIR	STACK_DIRECTION	/* Known at compile-time.  */
9900bf4279Sespie 
10000bf4279Sespie #else /* STACK_DIRECTION == 0; need run-time code.  */
10100bf4279Sespie 
10200bf4279Sespie static int stack_dir;		/* 1 or -1 once known.  */
10300bf4279Sespie #define	STACK_DIR	stack_dir
10400bf4279Sespie 
10500bf4279Sespie static void
find_stack_direction(void)106*20fce977Smiod find_stack_direction (void)
10700bf4279Sespie {
10800bf4279Sespie   static char *addr = NULL;	/* Address of first `dummy', once known.  */
10900bf4279Sespie   auto char dummy;		/* To get stack address.  */
11000bf4279Sespie 
11100bf4279Sespie   if (addr == NULL)
11200bf4279Sespie     {				/* Initial entry.  */
11300bf4279Sespie       addr = ADDRESS_FUNCTION (dummy);
11400bf4279Sespie 
11500bf4279Sespie       find_stack_direction ();	/* Recurse once.  */
11600bf4279Sespie     }
11700bf4279Sespie   else
11800bf4279Sespie     {
11900bf4279Sespie       /* Second entry.  */
12000bf4279Sespie       if (ADDRESS_FUNCTION (dummy) > addr)
12100bf4279Sespie 	stack_dir = 1;		/* Stack grew upward.  */
12200bf4279Sespie       else
12300bf4279Sespie 	stack_dir = -1;		/* Stack grew downward.  */
12400bf4279Sespie     }
12500bf4279Sespie }
12600bf4279Sespie 
12700bf4279Sespie #endif /* STACK_DIRECTION == 0 */
12800bf4279Sespie 
12900bf4279Sespie /* An "alloca header" is used to:
13000bf4279Sespie    (a) chain together all alloca'ed blocks;
13100bf4279Sespie    (b) keep track of stack depth.
13200bf4279Sespie 
13300bf4279Sespie    It is very important that sizeof(header) agree with malloc
13400bf4279Sespie    alignment chunk size.  The following default should work okay.  */
13500bf4279Sespie 
13600bf4279Sespie #ifndef	ALIGN_SIZE
13700bf4279Sespie #define	ALIGN_SIZE	sizeof(double)
13800bf4279Sespie #endif
13900bf4279Sespie 
14000bf4279Sespie typedef union hdr
14100bf4279Sespie {
14200bf4279Sespie   char align[ALIGN_SIZE];	/* To force sizeof(header).  */
14300bf4279Sespie   struct
14400bf4279Sespie     {
14500bf4279Sespie       union hdr *next;		/* For chaining headers.  */
14600bf4279Sespie       char *deep;		/* For stack depth measure.  */
14700bf4279Sespie     } h;
14800bf4279Sespie } header;
14900bf4279Sespie 
15000bf4279Sespie static header *last_alloca_header = NULL;	/* -> last alloca header.  */
15100bf4279Sespie 
15200bf4279Sespie /* Return a pointer to at least SIZE bytes of storage,
15300bf4279Sespie    which will be automatically reclaimed upon exit from
15400bf4279Sespie    the procedure that called alloca.  Originally, this space
15500bf4279Sespie    was supposed to be taken from the current stack frame of the
15600bf4279Sespie    caller, but that method cannot be made to work for some
15700bf4279Sespie    implementations of C, for example under Gould's UTX/32.  */
15800bf4279Sespie 
1599588ddcfSespie /* @undocumented C_alloca */
1609588ddcfSespie 
1619588ddcfSespie PTR
C_alloca(size_t size)162*20fce977Smiod C_alloca (size_t size)
16300bf4279Sespie {
16400bf4279Sespie   auto char probe;		/* Probes stack depth: */
16500bf4279Sespie   register char *depth = ADDRESS_FUNCTION (probe);
16600bf4279Sespie 
16700bf4279Sespie #if STACK_DIRECTION == 0
16800bf4279Sespie   if (STACK_DIR == 0)		/* Unknown growth direction.  */
16900bf4279Sespie     find_stack_direction ();
17000bf4279Sespie #endif
17100bf4279Sespie 
17200bf4279Sespie   /* Reclaim garbage, defined as all alloca'd storage that
17300bf4279Sespie      was allocated from deeper in the stack than currently.  */
17400bf4279Sespie 
17500bf4279Sespie   {
17600bf4279Sespie     register header *hp;	/* Traverses linked list.  */
17700bf4279Sespie 
17800bf4279Sespie     for (hp = last_alloca_header; hp != NULL;)
17900bf4279Sespie       if ((STACK_DIR > 0 && hp->h.deep > depth)
18000bf4279Sespie 	  || (STACK_DIR < 0 && hp->h.deep < depth))
18100bf4279Sespie 	{
18200bf4279Sespie 	  register header *np = hp->h.next;
18300bf4279Sespie 
1849588ddcfSespie 	  free ((PTR) hp);	/* Collect garbage.  */
18500bf4279Sespie 
18600bf4279Sespie 	  hp = np;		/* -> next header.  */
18700bf4279Sespie 	}
18800bf4279Sespie       else
18900bf4279Sespie 	break;			/* Rest are not deeper.  */
19000bf4279Sespie 
19100bf4279Sespie     last_alloca_header = hp;	/* -> last valid storage.  */
19200bf4279Sespie   }
19300bf4279Sespie 
19400bf4279Sespie   if (size == 0)
19500bf4279Sespie     return NULL;		/* No allocation required.  */
19600bf4279Sespie 
19700bf4279Sespie   /* Allocate combined header + user data storage.  */
19800bf4279Sespie 
19900bf4279Sespie   {
200*20fce977Smiod     register void *new_storage = XNEWVEC (char, sizeof (header) + size);
20100bf4279Sespie     /* Address of header.  */
20200bf4279Sespie 
203*20fce977Smiod     if (new_storage == 0)
20400bf4279Sespie       abort();
20500bf4279Sespie 
206*20fce977Smiod     ((header *) new_storage)->h.next = last_alloca_header;
207*20fce977Smiod     ((header *) new_storage)->h.deep = depth;
20800bf4279Sespie 
209*20fce977Smiod     last_alloca_header = (header *) new_storage;
21000bf4279Sespie 
21100bf4279Sespie     /* User storage begins just after header.  */
21200bf4279Sespie 
213*20fce977Smiod     return (PTR) ((char *) new_storage + sizeof (header));
21400bf4279Sespie   }
21500bf4279Sespie }
21600bf4279Sespie 
21700bf4279Sespie #if defined (CRAY) && defined (CRAY_STACKSEG_END)
21800bf4279Sespie 
21900bf4279Sespie #ifdef DEBUG_I00AFUNC
22000bf4279Sespie #include <stdio.h>
22100bf4279Sespie #endif
22200bf4279Sespie 
22300bf4279Sespie #ifndef CRAY_STACK
22400bf4279Sespie #define CRAY_STACK
22500bf4279Sespie #ifndef CRAY2
22600bf4279Sespie /* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */
22700bf4279Sespie struct stack_control_header
22800bf4279Sespie   {
22900bf4279Sespie     long shgrow:32;		/* Number of times stack has grown.  */
23000bf4279Sespie     long shaseg:32;		/* Size of increments to stack.  */
23100bf4279Sespie     long shhwm:32;		/* High water mark of stack.  */
23200bf4279Sespie     long shsize:32;		/* Current size of stack (all segments).  */
23300bf4279Sespie   };
23400bf4279Sespie 
23500bf4279Sespie /* The stack segment linkage control information occurs at
23600bf4279Sespie    the high-address end of a stack segment.  (The stack
23700bf4279Sespie    grows from low addresses to high addresses.)  The initial
23800bf4279Sespie    part of the stack segment linkage control information is
23900bf4279Sespie    0200 (octal) words.  This provides for register storage
24000bf4279Sespie    for the routine which overflows the stack.  */
24100bf4279Sespie 
24200bf4279Sespie struct stack_segment_linkage
24300bf4279Sespie   {
24400bf4279Sespie     long ss[0200];		/* 0200 overflow words.  */
24500bf4279Sespie     long sssize:32;		/* Number of words in this segment.  */
24600bf4279Sespie     long ssbase:32;		/* Offset to stack base.  */
24700bf4279Sespie     long:32;
24800bf4279Sespie     long sspseg:32;		/* Offset to linkage control of previous
24900bf4279Sespie 				   segment of stack.  */
25000bf4279Sespie     long:32;
25100bf4279Sespie     long sstcpt:32;		/* Pointer to task common address block.  */
25200bf4279Sespie     long sscsnm;		/* Private control structure number for
25300bf4279Sespie 				   microtasking.  */
25400bf4279Sespie     long ssusr1;		/* Reserved for user.  */
25500bf4279Sespie     long ssusr2;		/* Reserved for user.  */
25600bf4279Sespie     long sstpid;		/* Process ID for pid based multi-tasking.  */
25700bf4279Sespie     long ssgvup;		/* Pointer to multitasking thread giveup.  */
25800bf4279Sespie     long sscray[7];		/* Reserved for Cray Research.  */
25900bf4279Sespie     long ssa0;
26000bf4279Sespie     long ssa1;
26100bf4279Sespie     long ssa2;
26200bf4279Sespie     long ssa3;
26300bf4279Sespie     long ssa4;
26400bf4279Sespie     long ssa5;
26500bf4279Sespie     long ssa6;
26600bf4279Sespie     long ssa7;
26700bf4279Sespie     long sss0;
26800bf4279Sespie     long sss1;
26900bf4279Sespie     long sss2;
27000bf4279Sespie     long sss3;
27100bf4279Sespie     long sss4;
27200bf4279Sespie     long sss5;
27300bf4279Sespie     long sss6;
27400bf4279Sespie     long sss7;
27500bf4279Sespie   };
27600bf4279Sespie 
27700bf4279Sespie #else /* CRAY2 */
27800bf4279Sespie /* The following structure defines the vector of words
27900bf4279Sespie    returned by the STKSTAT library routine.  */
28000bf4279Sespie struct stk_stat
28100bf4279Sespie   {
28200bf4279Sespie     long now;			/* Current total stack size.  */
28300bf4279Sespie     long maxc;			/* Amount of contiguous space which would
28400bf4279Sespie 				   be required to satisfy the maximum
28500bf4279Sespie 				   stack demand to date.  */
28600bf4279Sespie     long high_water;		/* Stack high-water mark.  */
28700bf4279Sespie     long overflows;		/* Number of stack overflow ($STKOFEN) calls.  */
28800bf4279Sespie     long hits;			/* Number of internal buffer hits.  */
28900bf4279Sespie     long extends;		/* Number of block extensions.  */
29000bf4279Sespie     long stko_mallocs;		/* Block allocations by $STKOFEN.  */
29100bf4279Sespie     long underflows;		/* Number of stack underflow calls ($STKRETN).  */
29200bf4279Sespie     long stko_free;		/* Number of deallocations by $STKRETN.  */
29300bf4279Sespie     long stkm_free;		/* Number of deallocations by $STKMRET.  */
29400bf4279Sespie     long segments;		/* Current number of stack segments.  */
29500bf4279Sespie     long maxs;			/* Maximum number of stack segments so far.  */
29600bf4279Sespie     long pad_size;		/* Stack pad size.  */
29700bf4279Sespie     long current_address;	/* Current stack segment address.  */
29800bf4279Sespie     long current_size;		/* Current stack segment size.  This
29900bf4279Sespie 				   number is actually corrupted by STKSTAT to
30000bf4279Sespie 				   include the fifteen word trailer area.  */
30100bf4279Sespie     long initial_address;	/* Address of initial segment.  */
30200bf4279Sespie     long initial_size;		/* Size of initial segment.  */
30300bf4279Sespie   };
30400bf4279Sespie 
30500bf4279Sespie /* The following structure describes the data structure which trails
30600bf4279Sespie    any stack segment.  I think that the description in 'asdef' is
30700bf4279Sespie    out of date.  I only describe the parts that I am sure about.  */
30800bf4279Sespie 
30900bf4279Sespie struct stk_trailer
31000bf4279Sespie   {
31100bf4279Sespie     long this_address;		/* Address of this block.  */
31200bf4279Sespie     long this_size;		/* Size of this block (does not include
31300bf4279Sespie 				   this trailer).  */
31400bf4279Sespie     long unknown2;
31500bf4279Sespie     long unknown3;
31600bf4279Sespie     long link;			/* Address of trailer block of previous
31700bf4279Sespie 				   segment.  */
31800bf4279Sespie     long unknown5;
31900bf4279Sespie     long unknown6;
32000bf4279Sespie     long unknown7;
32100bf4279Sespie     long unknown8;
32200bf4279Sespie     long unknown9;
32300bf4279Sespie     long unknown10;
32400bf4279Sespie     long unknown11;
32500bf4279Sespie     long unknown12;
32600bf4279Sespie     long unknown13;
32700bf4279Sespie     long unknown14;
32800bf4279Sespie   };
32900bf4279Sespie 
33000bf4279Sespie #endif /* CRAY2 */
33100bf4279Sespie #endif /* not CRAY_STACK */
33200bf4279Sespie 
33300bf4279Sespie #ifdef CRAY2
33400bf4279Sespie /* Determine a "stack measure" for an arbitrary ADDRESS.
33500bf4279Sespie    I doubt that "lint" will like this much.  */
33600bf4279Sespie 
33700bf4279Sespie static long
i00afunc(long * address)33800bf4279Sespie i00afunc (long *address)
33900bf4279Sespie {
34000bf4279Sespie   struct stk_stat status;
34100bf4279Sespie   struct stk_trailer *trailer;
34200bf4279Sespie   long *block, size;
34300bf4279Sespie   long result = 0;
34400bf4279Sespie 
34500bf4279Sespie   /* We want to iterate through all of the segments.  The first
34600bf4279Sespie      step is to get the stack status structure.  We could do this
34700bf4279Sespie      more quickly and more directly, perhaps, by referencing the
34800bf4279Sespie      $LM00 common block, but I know that this works.  */
34900bf4279Sespie 
35000bf4279Sespie   STKSTAT (&status);
35100bf4279Sespie 
35200bf4279Sespie   /* Set up the iteration.  */
35300bf4279Sespie 
35400bf4279Sespie   trailer = (struct stk_trailer *) (status.current_address
35500bf4279Sespie 				    + status.current_size
35600bf4279Sespie 				    - 15);
35700bf4279Sespie 
35800bf4279Sespie   /* There must be at least one stack segment.  Therefore it is
35900bf4279Sespie      a fatal error if "trailer" is null.  */
36000bf4279Sespie 
36100bf4279Sespie   if (trailer == 0)
36200bf4279Sespie     abort ();
36300bf4279Sespie 
36400bf4279Sespie   /* Discard segments that do not contain our argument address.  */
36500bf4279Sespie 
36600bf4279Sespie   while (trailer != 0)
36700bf4279Sespie     {
36800bf4279Sespie       block = (long *) trailer->this_address;
36900bf4279Sespie       size = trailer->this_size;
37000bf4279Sespie       if (block == 0 || size == 0)
37100bf4279Sespie 	abort ();
37200bf4279Sespie       trailer = (struct stk_trailer *) trailer->link;
37300bf4279Sespie       if ((block <= address) && (address < (block + size)))
37400bf4279Sespie 	break;
37500bf4279Sespie     }
37600bf4279Sespie 
37700bf4279Sespie   /* Set the result to the offset in this segment and add the sizes
37800bf4279Sespie      of all predecessor segments.  */
37900bf4279Sespie 
38000bf4279Sespie   result = address - block;
38100bf4279Sespie 
38200bf4279Sespie   if (trailer == 0)
38300bf4279Sespie     {
38400bf4279Sespie       return result;
38500bf4279Sespie     }
38600bf4279Sespie 
38700bf4279Sespie   do
38800bf4279Sespie     {
38900bf4279Sespie       if (trailer->this_size <= 0)
39000bf4279Sespie 	abort ();
39100bf4279Sespie       result += trailer->this_size;
39200bf4279Sespie       trailer = (struct stk_trailer *) trailer->link;
39300bf4279Sespie     }
39400bf4279Sespie   while (trailer != 0);
39500bf4279Sespie 
39600bf4279Sespie   /* We are done.  Note that if you present a bogus address (one
39700bf4279Sespie      not in any segment), you will get a different number back, formed
39800bf4279Sespie      from subtracting the address of the first block.  This is probably
39900bf4279Sespie      not what you want.  */
40000bf4279Sespie 
40100bf4279Sespie   return (result);
40200bf4279Sespie }
40300bf4279Sespie 
40400bf4279Sespie #else /* not CRAY2 */
40500bf4279Sespie /* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP.
40600bf4279Sespie    Determine the number of the cell within the stack,
40700bf4279Sespie    given the address of the cell.  The purpose of this
40800bf4279Sespie    routine is to linearize, in some sense, stack addresses
40900bf4279Sespie    for alloca.  */
41000bf4279Sespie 
41100bf4279Sespie static long
i00afunc(long address)41200bf4279Sespie i00afunc (long address)
41300bf4279Sespie {
41400bf4279Sespie   long stkl = 0;
41500bf4279Sespie 
41600bf4279Sespie   long size, pseg, this_segment, stack;
41700bf4279Sespie   long result = 0;
41800bf4279Sespie 
41900bf4279Sespie   struct stack_segment_linkage *ssptr;
42000bf4279Sespie 
42100bf4279Sespie   /* Register B67 contains the address of the end of the
42200bf4279Sespie      current stack segment.  If you (as a subprogram) store
42300bf4279Sespie      your registers on the stack and find that you are past
42400bf4279Sespie      the contents of B67, you have overflowed the segment.
42500bf4279Sespie 
42600bf4279Sespie      B67 also points to the stack segment linkage control
42700bf4279Sespie      area, which is what we are really interested in.  */
42800bf4279Sespie 
42900bf4279Sespie   stkl = CRAY_STACKSEG_END ();
43000bf4279Sespie   ssptr = (struct stack_segment_linkage *) stkl;
43100bf4279Sespie 
43200bf4279Sespie   /* If one subtracts 'size' from the end of the segment,
43300bf4279Sespie      one has the address of the first word of the segment.
43400bf4279Sespie 
43500bf4279Sespie      If this is not the first segment, 'pseg' will be
43600bf4279Sespie      nonzero.  */
43700bf4279Sespie 
43800bf4279Sespie   pseg = ssptr->sspseg;
43900bf4279Sespie   size = ssptr->sssize;
44000bf4279Sespie 
44100bf4279Sespie   this_segment = stkl - size;
44200bf4279Sespie 
44300bf4279Sespie   /* It is possible that calling this routine itself caused
44400bf4279Sespie      a stack overflow.  Discard stack segments which do not
44500bf4279Sespie      contain the target address.  */
44600bf4279Sespie 
44700bf4279Sespie   while (!(this_segment <= address && address <= stkl))
44800bf4279Sespie     {
44900bf4279Sespie #ifdef DEBUG_I00AFUNC
45000bf4279Sespie       fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl);
45100bf4279Sespie #endif
45200bf4279Sespie       if (pseg == 0)
45300bf4279Sespie 	break;
45400bf4279Sespie       stkl = stkl - pseg;
45500bf4279Sespie       ssptr = (struct stack_segment_linkage *) stkl;
45600bf4279Sespie       size = ssptr->sssize;
45700bf4279Sespie       pseg = ssptr->sspseg;
45800bf4279Sespie       this_segment = stkl - size;
45900bf4279Sespie     }
46000bf4279Sespie 
46100bf4279Sespie   result = address - this_segment;
46200bf4279Sespie 
46300bf4279Sespie   /* If you subtract pseg from the current end of the stack,
46400bf4279Sespie      you get the address of the previous stack segment's end.
46500bf4279Sespie      This seems a little convoluted to me, but I'll bet you save
46600bf4279Sespie      a cycle somewhere.  */
46700bf4279Sespie 
46800bf4279Sespie   while (pseg != 0)
46900bf4279Sespie     {
47000bf4279Sespie #ifdef DEBUG_I00AFUNC
47100bf4279Sespie       fprintf (stderr, "%011o %011o\n", pseg, size);
47200bf4279Sespie #endif
47300bf4279Sespie       stkl = stkl - pseg;
47400bf4279Sespie       ssptr = (struct stack_segment_linkage *) stkl;
47500bf4279Sespie       size = ssptr->sssize;
47600bf4279Sespie       pseg = ssptr->sspseg;
47700bf4279Sespie       result += size;
47800bf4279Sespie     }
47900bf4279Sespie   return (result);
48000bf4279Sespie }
48100bf4279Sespie 
48200bf4279Sespie #endif /* not CRAY2 */
48300bf4279Sespie #endif /* CRAY */
484