[COFF] Terminology query - 'system process'?

Paul Winalski paul.winalski at gmail.com
Sun Dec 17 05:21:48 AEST 2023


On 12/15/23, Greg 'groggy' Lehey <grog at lemis.com> wrote:
>
> At least in assembler (I never programmed HLLs under MVS), by
> convention R13 pointed to the save area.  From memory, subroutine
> calls worked like:
>
>   LA    15,SUBR        load address of subroutine
>   BALR  14,15          call subroutine, storing address in R14
>
> The subroutine then starts
> with
>
>   STM  14,12,12(13)    save registers 14 to 12 (wraparound) in old save
> area
>   LA   14,SAVE         load address of our save area
>   ST   14,8(13)	       save in linkage of old save area
>   LR   13,14           and point to our save areas
>
> Returning from the subroutine was then
>
>   L    13,4(13)        restore old save area
>   LM   14,12,12(13)    restore the other registers
>   BR   14              and return to the caller
>
> Clearly this example isn't recursive, since it uses a static save
> area.  But with dynamic allocation it could be recursive.

Yes, that was the most common calling convention in S/360/370., and
the one that was used if you were implementing a subroutine package
for general use.  It has the advantage that the (caller-allocated)
register save area has room for all of the registers and so there is
no need to change the caller code if the callee is changed to use an
additional register.  It also makes it very convenient to implement
unwinding from an exception handler.  But it does burn 60 bytes for
the register save area and if you're programming for a S/360 model 25
with only 32K of user-available memory that can be significant.

Those writing their own assembly code typically cut corners on this
convention in order to reduce the memory footprint and the execution
time spent saving/restoring registers.

There's been long debate by ABI and compiler designers over the
relative merits of assigning the duties of allocating the register
save area  (RSA) and saving/restoring registers to either the caller
or the callee.  The IBM convention has the caller allocate the RSA and
the callee save and restore the register contents.  One can also have
a convention where the caller allocates an RSA and saves/restores the
registers it is actively using.  Or a convention where the callee
allocates the RSA and saves/restores the registers it has modified.
Each convention has its merits and demerits.

The IBM PL/I compiler for OS and OS/VS (but not DOS and DOS/VS) had
three routine declaration attributes to assist in optimization of
routine calls.  Absent any other information, the compiler must assume
the worst--that the subroutine call may modify any of the global
variables, and that it may be recursive.  IBM PL/I had a RECURSIVE
attribute to flag routines that are recursive.  It also had two
attributes--USES and SETS--to describe the global variables that are
either used by (USES) or changed by (SETS) the routine.  Global
variables not in the USES list did not have to be spilled before the
call.  Similarly, global variables not in the SETS list did not have
to be re-loaded after the call.

IBM dropped USES and SETS from the PL/I language with the S/370
compilers.  USES and SETS were something of a maintenance nightmare
for application programmers.  They were very error-prone.  If you
didn't keep the USES and SETS declarations up-to-date when you
modified a routine you could introduce all manner of subtle stale data
bugs.  On the compiler writers' side, data flow analysis wasn't yet
advanced enough to make good use of the USES and SETS information
anyway.  Modern compilers perform interprocedural analysis when they
can and derive accurate global variable data blow information on their
own.

-Paul W.


More information about the COFF mailing list