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