Subprograms

A subprogram is a sequence of instructions whose execution is invoked from one or more remote locations in a program, with the expectation that when the subprogram execution is complete, execution resumes at the instruction after the one that invoked the subprogram. In high-level languages, subprograms are also called subroutines, procedures, and functions. In object-oriented languages, they are usually called methods or constructors. In most modern high-level languages, subprograms can have parameters, local variables, and returned values.

At the assembly language level, use of subprograms requires subprogram linkage protocols. These protocols involve designating registers for special purposes and the use of special instructions for subprogram calls and returns.

Subprogram Linkage

Subprogram linkage refers to the mechanics of communication between a subprogram invoker (the caller) and the subprogram itself (the callee). The caller code consists of a sequence of instructions that

  1. sets up parameters,
  2. sets up a return address,
  3. jumps to the subprogram start address, and
  4. deals with the returned value.

The callee code consists of a sequence of instructions that

  1. implements the subprogram,
  2. sets up a returned value, and
  3. jumps to the return address.

Subprogram Instructions

Older CISC (Complex Instruction Set Processor) processors often provided complex subprogram call and subprogram return instructions that combined several of the steps in the caller and subprogram sides of linkage protocols. More modern RISC (Reduced Instruction Set Processor) processors just provides primitive instructions that can be combined to implement a variety of protocols. This makes it easier for a compiler to use different protocols depending on the context.

Typically, a RISC processor relies on data movement instructions for dealing with parameters and the return value. There are typically three instructions.

In a high-level language function with void returned value type, the return statement is often omitted from the code. This relies on the fact that the compiler automatically inserts the return jump. In machine or assembly language, it is essential to have the return jump at each exit from the subprogram code.

The Need for Linkage Protocols

Most subprograms have parameters and many have returned values. In addition, subprograms use registers as local variables. In moderate to large programs, it is easy to write code in which subprograms and their callers miscommunicate because of misunderstanding about how parameters and return values are passed between the caller and the subprogram. It is even easier for mistakes to arise because of conflicting use of registers for local purposes.

In order for subprograms to work, the calling code and the called subprogram must have a shared convention for the use of registers and dealing with parameters and returned values.

Subprogram Linkage Protocols

A subprogram linkage protocol is an agreement between caller code and subprogram code regarding

It is possible that different protocols are used by different subprograms in a program. However, different calls to the same subprogram must use the same protocol. Specifying a subprogram linkage protocol is part of the design of a subprogram. All calls must respect this protocol.

Register Usage Conventions

Register usage conventions specify how the various machine registers can be used. These conventions can deal with subprogram linkage in simple cases and they form a foundation for more general subprogram linkage protocols. Register usage designations fall into three broad categories:

These designations have significant implications for both subprograms and their callers.

Preserved Across Calls

When a register is designated as "preserved across calls", it means that the caller can count on the register having the same contents before and after a subprogram call.

If the subprogram uses one of these registers, it should take measures to save the register value before changing it and restore the value before returning. Registers that are specifically designated for use by main programs fall into the "preserved across calls" category.

Not Preserved Across Calls

If a register is designated as "not preserved across calls", it means that the caller cannot count on the register having the same contents before and after a subprogram call. Thus the subprogram can use the register freely.

If the caller puts a value into one of these registers before a subprogram call and needs the value after the call, then the caller has the responsibility of saving and restoring the value. Registers that are specifically designated for subprogram parameters, return values, or return addresses fall into the "not preserved across calls" category.

Dangerous

A register that is designated for special purpose use, other than in subprogram linkage, is generally considered "dangerous to use". Registers that are specifically designated for use by the operating system or the assembler fall into the "dangerous to use" category.