xref: /dflybsd-src/contrib/gcc-8.0/libiberty/alloca.c (revision 38fd149817dfbff97799f62fcb70be98c4e32523)
1*38fd1498Szrj /* alloca.c -- allocate automatically reclaimed memory
2*38fd1498Szrj    (Mostly) portable public-domain implementation -- D A Gwyn
3*38fd1498Szrj 
4*38fd1498Szrj    This implementation of the PWB library alloca function,
5*38fd1498Szrj    which is used to allocate space off the run-time stack so
6*38fd1498Szrj    that it is automatically reclaimed upon procedure exit,
7*38fd1498Szrj    was inspired by discussions with J. Q. Johnson of Cornell.
8*38fd1498Szrj    J.Otto Tennant <jot@cray.com> contributed the Cray support.
9*38fd1498Szrj 
10*38fd1498Szrj    There are some preprocessor constants that can
11*38fd1498Szrj    be defined when compiling for your specific system, for
12*38fd1498Szrj    improved efficiency; however, the defaults should be okay.
13*38fd1498Szrj 
14*38fd1498Szrj    The general concept of this implementation is to keep
15*38fd1498Szrj    track of all alloca-allocated blocks, and reclaim any
16*38fd1498Szrj    that are found to be deeper in the stack than the current
17*38fd1498Szrj    invocation.  This heuristic does not reclaim storage as
18*38fd1498Szrj    soon as it becomes invalid, but it will do so eventually.
19*38fd1498Szrj 
20*38fd1498Szrj    As a special case, alloca(0) reclaims storage without
21*38fd1498Szrj    allocating any.  It is a good idea to use alloca(0) in
22*38fd1498Szrj    your main control loop, etc. to force garbage collection.  */
23*38fd1498Szrj 
24*38fd1498Szrj /*
25*38fd1498Szrj 
26*38fd1498Szrj @deftypefn Replacement void* alloca (size_t @var{size})
27*38fd1498Szrj 
28*38fd1498Szrj This function allocates memory which will be automatically reclaimed
29*38fd1498Szrj after the procedure exits.  The @libib{} implementation does not free
30*38fd1498Szrj the memory immediately but will do so eventually during subsequent
31*38fd1498Szrj calls to this function.  Memory is allocated using @code{xmalloc} under
32*38fd1498Szrj normal circumstances.
33*38fd1498Szrj 
34*38fd1498Szrj The header file @file{alloca-conf.h} can be used in conjunction with the
35*38fd1498Szrj GNU Autoconf test @code{AC_FUNC_ALLOCA} to test for and properly make
36*38fd1498Szrj available this function.  The @code{AC_FUNC_ALLOCA} test requires that
37*38fd1498Szrj client code use a block of preprocessor code to be safe (see the Autoconf
38*38fd1498Szrj manual for more); this header incorporates that logic and more, including
39*38fd1498Szrj the possibility of a GCC built-in function.
40*38fd1498Szrj 
41*38fd1498Szrj @end deftypefn
42*38fd1498Szrj 
43*38fd1498Szrj */
44*38fd1498Szrj 
45*38fd1498Szrj #ifdef HAVE_CONFIG_H
46*38fd1498Szrj #include <config.h>
47*38fd1498Szrj #endif
48*38fd1498Szrj 
49*38fd1498Szrj #include <libiberty.h>
50*38fd1498Szrj 
51*38fd1498Szrj #ifdef HAVE_STRING_H
52*38fd1498Szrj #include <string.h>
53*38fd1498Szrj #endif
54*38fd1498Szrj #ifdef HAVE_STDLIB_H
55*38fd1498Szrj #include <stdlib.h>
56*38fd1498Szrj #endif
57*38fd1498Szrj 
58*38fd1498Szrj /* These variables are used by the ASTRDUP implementation that relies
59*38fd1498Szrj    on C_alloca.  */
60*38fd1498Szrj #ifdef __cplusplus
61*38fd1498Szrj extern "C" {
62*38fd1498Szrj #endif /* __cplusplus */
63*38fd1498Szrj const char *libiberty_optr;
64*38fd1498Szrj char *libiberty_nptr;
65*38fd1498Szrj unsigned long libiberty_len;
66*38fd1498Szrj #ifdef __cplusplus
67*38fd1498Szrj }
68*38fd1498Szrj #endif /* __cplusplus */
69*38fd1498Szrj 
70*38fd1498Szrj /* If your stack is a linked list of frames, you have to
71*38fd1498Szrj    provide an "address metric" ADDRESS_FUNCTION macro.  */
72*38fd1498Szrj 
73*38fd1498Szrj #if defined (CRAY) && defined (CRAY_STACKSEG_END)
74*38fd1498Szrj static long i00afunc ();
75*38fd1498Szrj #define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg))
76*38fd1498Szrj #else
77*38fd1498Szrj #define ADDRESS_FUNCTION(arg) &(arg)
78*38fd1498Szrj #endif
79*38fd1498Szrj 
80*38fd1498Szrj #ifndef NULL
81*38fd1498Szrj #define	NULL	0
82*38fd1498Szrj #endif
83*38fd1498Szrj 
84*38fd1498Szrj /* Define STACK_DIRECTION if you know the direction of stack
85*38fd1498Szrj    growth for your system; otherwise it will be automatically
86*38fd1498Szrj    deduced at run-time.
87*38fd1498Szrj 
88*38fd1498Szrj    STACK_DIRECTION > 0 => grows toward higher addresses
89*38fd1498Szrj    STACK_DIRECTION < 0 => grows toward lower addresses
90*38fd1498Szrj    STACK_DIRECTION = 0 => direction of growth unknown  */
91*38fd1498Szrj 
92*38fd1498Szrj #ifndef STACK_DIRECTION
93*38fd1498Szrj #define	STACK_DIRECTION	0	/* Direction unknown.  */
94*38fd1498Szrj #endif
95*38fd1498Szrj 
96*38fd1498Szrj #if STACK_DIRECTION != 0
97*38fd1498Szrj 
98*38fd1498Szrj #define	STACK_DIR	STACK_DIRECTION	/* Known at compile-time.  */
99*38fd1498Szrj 
100*38fd1498Szrj #else /* STACK_DIRECTION == 0; need run-time code.  */
101*38fd1498Szrj 
102*38fd1498Szrj static int stack_dir;		/* 1 or -1 once known.  */
103*38fd1498Szrj #define	STACK_DIR	stack_dir
104*38fd1498Szrj 
105*38fd1498Szrj static void
find_stack_direction(void)106*38fd1498Szrj find_stack_direction (void)
107*38fd1498Szrj {
108*38fd1498Szrj   static char *addr = NULL;	/* Address of first `dummy', once known.  */
109*38fd1498Szrj   auto char dummy;		/* To get stack address.  */
110*38fd1498Szrj 
111*38fd1498Szrj   if (addr == NULL)
112*38fd1498Szrj     {				/* Initial entry.  */
113*38fd1498Szrj       addr = ADDRESS_FUNCTION (dummy);
114*38fd1498Szrj 
115*38fd1498Szrj       find_stack_direction ();	/* Recurse once.  */
116*38fd1498Szrj     }
117*38fd1498Szrj   else
118*38fd1498Szrj     {
119*38fd1498Szrj       /* Second entry.  */
120*38fd1498Szrj       if (ADDRESS_FUNCTION (dummy) > addr)
121*38fd1498Szrj 	stack_dir = 1;		/* Stack grew upward.  */
122*38fd1498Szrj       else
123*38fd1498Szrj 	stack_dir = -1;		/* Stack grew downward.  */
124*38fd1498Szrj     }
125*38fd1498Szrj }
126*38fd1498Szrj 
127*38fd1498Szrj #endif /* STACK_DIRECTION == 0 */
128*38fd1498Szrj 
129*38fd1498Szrj /* An "alloca header" is used to:
130*38fd1498Szrj    (a) chain together all alloca'ed blocks;
131*38fd1498Szrj    (b) keep track of stack depth.
132*38fd1498Szrj 
133*38fd1498Szrj    It is very important that sizeof(header) agree with malloc
134*38fd1498Szrj    alignment chunk size.  The following default should work okay.  */
135*38fd1498Szrj 
136*38fd1498Szrj #ifndef	ALIGN_SIZE
137*38fd1498Szrj #define	ALIGN_SIZE	sizeof(double)
138*38fd1498Szrj #endif
139*38fd1498Szrj 
140*38fd1498Szrj typedef union hdr
141*38fd1498Szrj {
142*38fd1498Szrj   char align[ALIGN_SIZE];	/* To force sizeof(header).  */
143*38fd1498Szrj   struct
144*38fd1498Szrj     {
145*38fd1498Szrj       union hdr *next;		/* For chaining headers.  */
146*38fd1498Szrj       char *deep;		/* For stack depth measure.  */
147*38fd1498Szrj     } h;
148*38fd1498Szrj } header;
149*38fd1498Szrj 
150*38fd1498Szrj static header *last_alloca_header = NULL;	/* -> last alloca header.  */
151*38fd1498Szrj 
152*38fd1498Szrj /* Return a pointer to at least SIZE bytes of storage,
153*38fd1498Szrj    which will be automatically reclaimed upon exit from
154*38fd1498Szrj    the procedure that called alloca.  Originally, this space
155*38fd1498Szrj    was supposed to be taken from the current stack frame of the
156*38fd1498Szrj    caller, but that method cannot be made to work for some
157*38fd1498Szrj    implementations of C, for example under Gould's UTX/32.  */
158*38fd1498Szrj 
159*38fd1498Szrj /* @undocumented C_alloca */
160*38fd1498Szrj 
161*38fd1498Szrj PTR
C_alloca(size_t size)162*38fd1498Szrj C_alloca (size_t size)
163*38fd1498Szrj {
164*38fd1498Szrj   auto char probe;		/* Probes stack depth: */
165*38fd1498Szrj   register char *depth = ADDRESS_FUNCTION (probe);
166*38fd1498Szrj 
167*38fd1498Szrj #if STACK_DIRECTION == 0
168*38fd1498Szrj   if (STACK_DIR == 0)		/* Unknown growth direction.  */
169*38fd1498Szrj     find_stack_direction ();
170*38fd1498Szrj #endif
171*38fd1498Szrj 
172*38fd1498Szrj   /* Reclaim garbage, defined as all alloca'd storage that
173*38fd1498Szrj      was allocated from deeper in the stack than currently.  */
174*38fd1498Szrj 
175*38fd1498Szrj   {
176*38fd1498Szrj     register header *hp;	/* Traverses linked list.  */
177*38fd1498Szrj 
178*38fd1498Szrj     for (hp = last_alloca_header; hp != NULL;)
179*38fd1498Szrj       if ((STACK_DIR > 0 && hp->h.deep > depth)
180*38fd1498Szrj 	  || (STACK_DIR < 0 && hp->h.deep < depth))
181*38fd1498Szrj 	{
182*38fd1498Szrj 	  register header *np = hp->h.next;
183*38fd1498Szrj 
184*38fd1498Szrj 	  free ((PTR) hp);	/* Collect garbage.  */
185*38fd1498Szrj 
186*38fd1498Szrj 	  hp = np;		/* -> next header.  */
187*38fd1498Szrj 	}
188*38fd1498Szrj       else
189*38fd1498Szrj 	break;			/* Rest are not deeper.  */
190*38fd1498Szrj 
191*38fd1498Szrj     last_alloca_header = hp;	/* -> last valid storage.  */
192*38fd1498Szrj   }
193*38fd1498Szrj 
194*38fd1498Szrj   if (size == 0)
195*38fd1498Szrj     return NULL;		/* No allocation required.  */
196*38fd1498Szrj 
197*38fd1498Szrj   /* Allocate combined header + user data storage.  */
198*38fd1498Szrj 
199*38fd1498Szrj   {
200*38fd1498Szrj     register void *new_storage = XNEWVEC (char, sizeof (header) + size);
201*38fd1498Szrj     /* Address of header.  */
202*38fd1498Szrj 
203*38fd1498Szrj     if (new_storage == 0)
204*38fd1498Szrj       abort();
205*38fd1498Szrj 
206*38fd1498Szrj     ((header *) new_storage)->h.next = last_alloca_header;
207*38fd1498Szrj     ((header *) new_storage)->h.deep = depth;
208*38fd1498Szrj 
209*38fd1498Szrj     last_alloca_header = (header *) new_storage;
210*38fd1498Szrj 
211*38fd1498Szrj     /* User storage begins just after header.  */
212*38fd1498Szrj 
213*38fd1498Szrj     return (PTR) ((char *) new_storage + sizeof (header));
214*38fd1498Szrj   }
215*38fd1498Szrj }
216*38fd1498Szrj 
217*38fd1498Szrj #if defined (CRAY) && defined (CRAY_STACKSEG_END)
218*38fd1498Szrj 
219*38fd1498Szrj #ifdef DEBUG_I00AFUNC
220*38fd1498Szrj #include <stdio.h>
221*38fd1498Szrj #endif
222*38fd1498Szrj 
223*38fd1498Szrj #ifndef CRAY_STACK
224*38fd1498Szrj #define CRAY_STACK
225*38fd1498Szrj #ifndef CRAY2
226*38fd1498Szrj /* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */
227*38fd1498Szrj struct stack_control_header
228*38fd1498Szrj   {
229*38fd1498Szrj     long shgrow:32;		/* Number of times stack has grown.  */
230*38fd1498Szrj     long shaseg:32;		/* Size of increments to stack.  */
231*38fd1498Szrj     long shhwm:32;		/* High water mark of stack.  */
232*38fd1498Szrj     long shsize:32;		/* Current size of stack (all segments).  */
233*38fd1498Szrj   };
234*38fd1498Szrj 
235*38fd1498Szrj /* The stack segment linkage control information occurs at
236*38fd1498Szrj    the high-address end of a stack segment.  (The stack
237*38fd1498Szrj    grows from low addresses to high addresses.)  The initial
238*38fd1498Szrj    part of the stack segment linkage control information is
239*38fd1498Szrj    0200 (octal) words.  This provides for register storage
240*38fd1498Szrj    for the routine which overflows the stack.  */
241*38fd1498Szrj 
242*38fd1498Szrj struct stack_segment_linkage
243*38fd1498Szrj   {
244*38fd1498Szrj     long ss[0200];		/* 0200 overflow words.  */
245*38fd1498Szrj     long sssize:32;		/* Number of words in this segment.  */
246*38fd1498Szrj     long ssbase:32;		/* Offset to stack base.  */
247*38fd1498Szrj     long:32;
248*38fd1498Szrj     long sspseg:32;		/* Offset to linkage control of previous
249*38fd1498Szrj 				   segment of stack.  */
250*38fd1498Szrj     long:32;
251*38fd1498Szrj     long sstcpt:32;		/* Pointer to task common address block.  */
252*38fd1498Szrj     long sscsnm;		/* Private control structure number for
253*38fd1498Szrj 				   microtasking.  */
254*38fd1498Szrj     long ssusr1;		/* Reserved for user.  */
255*38fd1498Szrj     long ssusr2;		/* Reserved for user.  */
256*38fd1498Szrj     long sstpid;		/* Process ID for pid based multi-tasking.  */
257*38fd1498Szrj     long ssgvup;		/* Pointer to multitasking thread giveup.  */
258*38fd1498Szrj     long sscray[7];		/* Reserved for Cray Research.  */
259*38fd1498Szrj     long ssa0;
260*38fd1498Szrj     long ssa1;
261*38fd1498Szrj     long ssa2;
262*38fd1498Szrj     long ssa3;
263*38fd1498Szrj     long ssa4;
264*38fd1498Szrj     long ssa5;
265*38fd1498Szrj     long ssa6;
266*38fd1498Szrj     long ssa7;
267*38fd1498Szrj     long sss0;
268*38fd1498Szrj     long sss1;
269*38fd1498Szrj     long sss2;
270*38fd1498Szrj     long sss3;
271*38fd1498Szrj     long sss4;
272*38fd1498Szrj     long sss5;
273*38fd1498Szrj     long sss6;
274*38fd1498Szrj     long sss7;
275*38fd1498Szrj   };
276*38fd1498Szrj 
277*38fd1498Szrj #else /* CRAY2 */
278*38fd1498Szrj /* The following structure defines the vector of words
279*38fd1498Szrj    returned by the STKSTAT library routine.  */
280*38fd1498Szrj struct stk_stat
281*38fd1498Szrj   {
282*38fd1498Szrj     long now;			/* Current total stack size.  */
283*38fd1498Szrj     long maxc;			/* Amount of contiguous space which would
284*38fd1498Szrj 				   be required to satisfy the maximum
285*38fd1498Szrj 				   stack demand to date.  */
286*38fd1498Szrj     long high_water;		/* Stack high-water mark.  */
287*38fd1498Szrj     long overflows;		/* Number of stack overflow ($STKOFEN) calls.  */
288*38fd1498Szrj     long hits;			/* Number of internal buffer hits.  */
289*38fd1498Szrj     long extends;		/* Number of block extensions.  */
290*38fd1498Szrj     long stko_mallocs;		/* Block allocations by $STKOFEN.  */
291*38fd1498Szrj     long underflows;		/* Number of stack underflow calls ($STKRETN).  */
292*38fd1498Szrj     long stko_free;		/* Number of deallocations by $STKRETN.  */
293*38fd1498Szrj     long stkm_free;		/* Number of deallocations by $STKMRET.  */
294*38fd1498Szrj     long segments;		/* Current number of stack segments.  */
295*38fd1498Szrj     long maxs;			/* Maximum number of stack segments so far.  */
296*38fd1498Szrj     long pad_size;		/* Stack pad size.  */
297*38fd1498Szrj     long current_address;	/* Current stack segment address.  */
298*38fd1498Szrj     long current_size;		/* Current stack segment size.  This
299*38fd1498Szrj 				   number is actually corrupted by STKSTAT to
300*38fd1498Szrj 				   include the fifteen word trailer area.  */
301*38fd1498Szrj     long initial_address;	/* Address of initial segment.  */
302*38fd1498Szrj     long initial_size;		/* Size of initial segment.  */
303*38fd1498Szrj   };
304*38fd1498Szrj 
305*38fd1498Szrj /* The following structure describes the data structure which trails
306*38fd1498Szrj    any stack segment.  I think that the description in 'asdef' is
307*38fd1498Szrj    out of date.  I only describe the parts that I am sure about.  */
308*38fd1498Szrj 
309*38fd1498Szrj struct stk_trailer
310*38fd1498Szrj   {
311*38fd1498Szrj     long this_address;		/* Address of this block.  */
312*38fd1498Szrj     long this_size;		/* Size of this block (does not include
313*38fd1498Szrj 				   this trailer).  */
314*38fd1498Szrj     long unknown2;
315*38fd1498Szrj     long unknown3;
316*38fd1498Szrj     long link;			/* Address of trailer block of previous
317*38fd1498Szrj 				   segment.  */
318*38fd1498Szrj     long unknown5;
319*38fd1498Szrj     long unknown6;
320*38fd1498Szrj     long unknown7;
321*38fd1498Szrj     long unknown8;
322*38fd1498Szrj     long unknown9;
323*38fd1498Szrj     long unknown10;
324*38fd1498Szrj     long unknown11;
325*38fd1498Szrj     long unknown12;
326*38fd1498Szrj     long unknown13;
327*38fd1498Szrj     long unknown14;
328*38fd1498Szrj   };
329*38fd1498Szrj 
330*38fd1498Szrj #endif /* CRAY2 */
331*38fd1498Szrj #endif /* not CRAY_STACK */
332*38fd1498Szrj 
333*38fd1498Szrj #ifdef CRAY2
334*38fd1498Szrj /* Determine a "stack measure" for an arbitrary ADDRESS.
335*38fd1498Szrj    I doubt that "lint" will like this much.  */
336*38fd1498Szrj 
337*38fd1498Szrj static long
i00afunc(long * address)338*38fd1498Szrj i00afunc (long *address)
339*38fd1498Szrj {
340*38fd1498Szrj   struct stk_stat status;
341*38fd1498Szrj   struct stk_trailer *trailer;
342*38fd1498Szrj   long *block, size;
343*38fd1498Szrj   long result = 0;
344*38fd1498Szrj 
345*38fd1498Szrj   /* We want to iterate through all of the segments.  The first
346*38fd1498Szrj      step is to get the stack status structure.  We could do this
347*38fd1498Szrj      more quickly and more directly, perhaps, by referencing the
348*38fd1498Szrj      $LM00 common block, but I know that this works.  */
349*38fd1498Szrj 
350*38fd1498Szrj   STKSTAT (&status);
351*38fd1498Szrj 
352*38fd1498Szrj   /* Set up the iteration.  */
353*38fd1498Szrj 
354*38fd1498Szrj   trailer = (struct stk_trailer *) (status.current_address
355*38fd1498Szrj 				    + status.current_size
356*38fd1498Szrj 				    - 15);
357*38fd1498Szrj 
358*38fd1498Szrj   /* There must be at least one stack segment.  Therefore it is
359*38fd1498Szrj      a fatal error if "trailer" is null.  */
360*38fd1498Szrj 
361*38fd1498Szrj   if (trailer == 0)
362*38fd1498Szrj     abort ();
363*38fd1498Szrj 
364*38fd1498Szrj   /* Discard segments that do not contain our argument address.  */
365*38fd1498Szrj 
366*38fd1498Szrj   while (trailer != 0)
367*38fd1498Szrj     {
368*38fd1498Szrj       block = (long *) trailer->this_address;
369*38fd1498Szrj       size = trailer->this_size;
370*38fd1498Szrj       if (block == 0 || size == 0)
371*38fd1498Szrj 	abort ();
372*38fd1498Szrj       trailer = (struct stk_trailer *) trailer->link;
373*38fd1498Szrj       if ((block <= address) && (address < (block + size)))
374*38fd1498Szrj 	break;
375*38fd1498Szrj     }
376*38fd1498Szrj 
377*38fd1498Szrj   /* Set the result to the offset in this segment and add the sizes
378*38fd1498Szrj      of all predecessor segments.  */
379*38fd1498Szrj 
380*38fd1498Szrj   result = address - block;
381*38fd1498Szrj 
382*38fd1498Szrj   if (trailer == 0)
383*38fd1498Szrj     {
384*38fd1498Szrj       return result;
385*38fd1498Szrj     }
386*38fd1498Szrj 
387*38fd1498Szrj   do
388*38fd1498Szrj     {
389*38fd1498Szrj       if (trailer->this_size <= 0)
390*38fd1498Szrj 	abort ();
391*38fd1498Szrj       result += trailer->this_size;
392*38fd1498Szrj       trailer = (struct stk_trailer *) trailer->link;
393*38fd1498Szrj     }
394*38fd1498Szrj   while (trailer != 0);
395*38fd1498Szrj 
396*38fd1498Szrj   /* We are done.  Note that if you present a bogus address (one
397*38fd1498Szrj      not in any segment), you will get a different number back, formed
398*38fd1498Szrj      from subtracting the address of the first block.  This is probably
399*38fd1498Szrj      not what you want.  */
400*38fd1498Szrj 
401*38fd1498Szrj   return (result);
402*38fd1498Szrj }
403*38fd1498Szrj 
404*38fd1498Szrj #else /* not CRAY2 */
405*38fd1498Szrj /* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP.
406*38fd1498Szrj    Determine the number of the cell within the stack,
407*38fd1498Szrj    given the address of the cell.  The purpose of this
408*38fd1498Szrj    routine is to linearize, in some sense, stack addresses
409*38fd1498Szrj    for alloca.  */
410*38fd1498Szrj 
411*38fd1498Szrj static long
i00afunc(long address)412*38fd1498Szrj i00afunc (long address)
413*38fd1498Szrj {
414*38fd1498Szrj   long stkl = 0;
415*38fd1498Szrj 
416*38fd1498Szrj   long size, pseg, this_segment, stack;
417*38fd1498Szrj   long result = 0;
418*38fd1498Szrj 
419*38fd1498Szrj   struct stack_segment_linkage *ssptr;
420*38fd1498Szrj 
421*38fd1498Szrj   /* Register B67 contains the address of the end of the
422*38fd1498Szrj      current stack segment.  If you (as a subprogram) store
423*38fd1498Szrj      your registers on the stack and find that you are past
424*38fd1498Szrj      the contents of B67, you have overflowed the segment.
425*38fd1498Szrj 
426*38fd1498Szrj      B67 also points to the stack segment linkage control
427*38fd1498Szrj      area, which is what we are really interested in.  */
428*38fd1498Szrj 
429*38fd1498Szrj   stkl = CRAY_STACKSEG_END ();
430*38fd1498Szrj   ssptr = (struct stack_segment_linkage *) stkl;
431*38fd1498Szrj 
432*38fd1498Szrj   /* If one subtracts 'size' from the end of the segment,
433*38fd1498Szrj      one has the address of the first word of the segment.
434*38fd1498Szrj 
435*38fd1498Szrj      If this is not the first segment, 'pseg' will be
436*38fd1498Szrj      nonzero.  */
437*38fd1498Szrj 
438*38fd1498Szrj   pseg = ssptr->sspseg;
439*38fd1498Szrj   size = ssptr->sssize;
440*38fd1498Szrj 
441*38fd1498Szrj   this_segment = stkl - size;
442*38fd1498Szrj 
443*38fd1498Szrj   /* It is possible that calling this routine itself caused
444*38fd1498Szrj      a stack overflow.  Discard stack segments which do not
445*38fd1498Szrj      contain the target address.  */
446*38fd1498Szrj 
447*38fd1498Szrj   while (!(this_segment <= address && address <= stkl))
448*38fd1498Szrj     {
449*38fd1498Szrj #ifdef DEBUG_I00AFUNC
450*38fd1498Szrj       fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl);
451*38fd1498Szrj #endif
452*38fd1498Szrj       if (pseg == 0)
453*38fd1498Szrj 	break;
454*38fd1498Szrj       stkl = stkl - pseg;
455*38fd1498Szrj       ssptr = (struct stack_segment_linkage *) stkl;
456*38fd1498Szrj       size = ssptr->sssize;
457*38fd1498Szrj       pseg = ssptr->sspseg;
458*38fd1498Szrj       this_segment = stkl - size;
459*38fd1498Szrj     }
460*38fd1498Szrj 
461*38fd1498Szrj   result = address - this_segment;
462*38fd1498Szrj 
463*38fd1498Szrj   /* If you subtract pseg from the current end of the stack,
464*38fd1498Szrj      you get the address of the previous stack segment's end.
465*38fd1498Szrj      This seems a little convoluted to me, but I'll bet you save
466*38fd1498Szrj      a cycle somewhere.  */
467*38fd1498Szrj 
468*38fd1498Szrj   while (pseg != 0)
469*38fd1498Szrj     {
470*38fd1498Szrj #ifdef DEBUG_I00AFUNC
471*38fd1498Szrj       fprintf (stderr, "%011o %011o\n", pseg, size);
472*38fd1498Szrj #endif
473*38fd1498Szrj       stkl = stkl - pseg;
474*38fd1498Szrj       ssptr = (struct stack_segment_linkage *) stkl;
475*38fd1498Szrj       size = ssptr->sssize;
476*38fd1498Szrj       pseg = ssptr->sspseg;
477*38fd1498Szrj       result += size;
478*38fd1498Szrj     }
479*38fd1498Szrj   return (result);
480*38fd1498Szrj }
481*38fd1498Szrj 
482*38fd1498Szrj #endif /* not CRAY2 */
483*38fd1498Szrj #endif /* CRAY */
484