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