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