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