CALL - single segment Pascal calling sequence.

In order to understand the calling sequence, a few words must be said first about the format of the stack.

The stack pointer (sp = AR7) points to a word containing the stack pointer of its caller. Immediately before this word are two words of linkage (at offsets -2, and -1) that are used by routines CALLED by the current routine. These three words (offsets -2, -1 and 0 from the stack pointer) are collectively referred to as the "linkage area".

Arguments to a routine are located at positive offsets from the stack pointer. The first argument is at offset 1, the next at offset 2, and so on. Furthermore, each successive argument may be located by adding one (or whatever the length of the argument) from a pointer to the previous argument (i.e. they occupy increasing core addresses.) If the argument requires double word alignment, a word of filler may be allocated.

Following the arguments are N words of display, where N is the nesting level of the routine. The display is double word aligned. Following the display are local variables and compiler temporary variables. After this is the space that will be used as a linkage area by called routines. This is followed by the space where arguments to these routines are placed. There may be more compiler temporaries after this, and finally the stack frame ends with another "secondary linkage area".

Thus the stack space required by a routine is given by

Extra padding words are added, if needed, before any items requiring even or odd word alignment. The stack frame length is always rounded up to an even number.

The offset to the linkage area of the callee is not fixed and varies with the amount of temporary space currently in use. This is most obvious when a function must be called while the arguments to another function are being evaluated. In this case, the space occupied by already evaluated arguments is considered to be active temporary, and the arguments and linkage for the second call are placed after this. The stack frame size calculation is done for the maximum stack usage.

The stack pointer is stored in address register AR7. It is often referred to simply as "sp". It points to the stack frame of the currently active routine. The stack grows upward away from zero. AR7 always contains an odd value, so argument 1 is aligned on an even word boundary.

For a call, the arguments are computed and stored in the argument area, except for the first two arguments (or first two words of arguments if the first argument is longer than one word). The first two words are passed in the A and Q registers, although space is allocated in the argument area for the callee to save them. During the call sequence, ar7 is advanced to point to the linkage area preceding the arguments of the called routine, and the previous contents of the stack pointer are stored in that linkage area.

Note therefore, that the stack frame of the callee overlaps that of the caller from the argument space on.

A standard call to a Pascal routine "x" which has three arguments, whose values are given by "a", "b" and "c", could be written

lda    c,,ar7  Fill in args
sta    m+3,,ar7
ldq    b,,ar7
lda    a,,ar7
eax7   display,,ar7     Load display pointer
tsx1   x
zero   m,n

where "n" gives the number of words of arguments passed to "x", (in this case, n=3), and "m" (which is always even) gives the amount to advance the stack pointer to point to the new stack frame. That is, "m" is the amount of stack that is private to the caller, not overlapped with the next frame.

At the entry to any Pascal routine, the routine must execute some stack setup code, to reserve sufficient stack for it to run in, and to save the previous environment. As this code is invariant, it has been arranged that it be called as a small subroutine from the Pascal routine. The amount of stack space required varies of course from routine to routine, so a word containing the stack frame size is placed following the call to the entry routine. The frame size is always an even number of words. The value must be at least eight (8) to allow for a display, and the primary and secondary linkage areas.

The entry routine is called ".entry" and is invoked as follows.

       symref  .entry
x      tsx0    .entry
       zero    fsize,dpoint

where "fsize" is the number of words of stack required and "dpoint" is a pointer (possibly zero) to optional debug information. Normally, "fsize" is not used by the entry routine, but a pointer to it is stored in the linkage area. It is used together with the current stack pointer to find the true end of the stack. This may be used to check for stack overflow, to initialize the stack after the arguments for debugging purposes, or by an asynchronous operation such as the break handler to find some free stack space to work with.

The called function must also make a display describing its active scope. On entry, X7 will contain a pointer to a copy of the display for the statically enclosing procedure. Except in the case of a passed procedure, this will be the stack frame of the caller. The new display may be produced as follows.

awdx   ,x7,ar0 Point to enclosing stack frame
mlr    (1),(1) Copy display
adsc9  0,,n*4-4,ar0
adsc9  d,,n*4-4,ar7
sar7   d+n-1,,ar7 Put current frame into display

where "n" is the nesting level of the procedure, and "d" is the offset to the callee's display. In the case where "n" equals one (i.e. there is no enclosing procedure) the copy code (awdx, mlr) is not generated.

To leave a function normally and return to the calling routine, another small routine is invoked. It is called ".retrn". This pops the stack and restores the values of various registers. It is invoked by

symref .retrn
tra    .retrn

If there is to be a return value, it is loaded into the Q register (if integer), the AQ register (if double-word integer), or the EAQ if floating-point.

If the procedure exit is via a goto, the following code is generated.

lda   d+n-1,,ar7  Get stack pointer from display
eaq   label       Location to jump to
tsx0  .goto       Routine to unwind stack
zero  m,2

where "n" is the nesting level of the procedure containing the label, and "d" is the offset to the display of the current procedure. It would be possible to just load the stack pointer and jump to the label, but this would not spring traps set to do such things as closing tempfiles opened in between.

Throughout the above discussion only one-word objects have been considered. Objects that occupy several words are handled similarly; the offset for the following object is simply larger by the appropriate amount. The same comment applies to double-precision objects (which must be properly aligned).

Stack Frame Size:

Since the offset from an address register is only a 15 bit field, this imposes a limit of 16384 words on the size of a stack frame. Therefore the sum total of all the variables, temporaries and arguments needed by a procedure or a function must be less than this. If larger arrays are needed, they must either be statically allocated globally, or allocated dynamically via NEW.

See Also:

The Pascal stack is compatible with the stack frame used by the B language. For a more complete discussion of the stack, including the use of the secondary linkage area, see "expl b environment".

Copyright © 1996, Thinkage Ltd.