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