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