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