C55xx: How a Function Makes a Call
How a Function Makes a Call. Taken from document spru281f.pdf by Texas Instruments.
1 Function Structure and Calling Conventions
The C/C++ compiler imposes a strict set of rules on function calls. Except for special run-time-support functions, any function that calls or is called by a C function must follow these rules. Failure to adhere to these rules can disrupt the C/C++ environment and cause a program to fail.
Figure 1 illustrates a typical function call. In this example, parameters are passed to the function, and the function uses local variables and calls another function. Up to 10 parameters are passed in registers. This example also shows allocation of a local frame and argument block for the called function. The stack must be aligned to a 32-bit (even 16-bit word) boundary before calling a function. The parent function pushes the 16-bit return PC. The term argument block refers to the part of the local frame used to pass arguments to other functions. Parameters are passed to a function by moving them into the argument block rather than pushing them on the stack. The local frame and argument block are allocated at the same time.
Figure 1. Use of the Stack During a Function Call
2 How a Function Makes a Call
A function (parent function) performs the following tasks when it calls another function. A C routine should be accessed with a call (CALL) instruction and never with a branch (B) instruction.
- Arguments to a function are placed in registers or on the stack.
- For a function declared with an ellipsis (indicating that it is called with varying numbers of arguments), the last explicitly-declared argument is passed on the stack, followed by the rest of the arguments. Its stack address can act as a reference for accessing the undeclared argu-ments. Arguments declared before the last explicit argument follow rules shown below.
- In general, when an argument is passed to a function, the compiler assigns to it a particular class. It then places it in a register (if available) according to its class. The compiler uses three classes:
- data pointer (int *, long *, etc.)
- 16-bit data (char, short, int)
- 32-bit data (long, float, double, function pointers) or 40-bit (long long)
- If the argument is a pointer to any type of data, it is considered a data pointer.
- If an argument will fit into a 16-bit register, it is considered 16-bit data.
- Otherwise, it is considered 32-bit data.
- 40-bit data is passed by using the entire register rather than just the lower 32 bits.
- A structure of two words (32 bits) or less is treated like a 32-bit data argument. It is passed in a register, if available.
- A structure larger than two words is passed by reference. The compiler will pass the address of the structure as a pointer. This pointer is treated like a data pointer argument.
- If the called (child) function returns a struct or union value, the parent function allocates space on the local stack for a structure of that size. The parent then passes the address of that space as a hidden first argument to the called function. This pointer is treated like a data pointer argument. In effect, the function call is transformed from:
struct s result = fn(x, y);
fn(&result, x, y);
- The arguments are assigned to registers in the order that the arguments are listed in the prototype. They are placed in the following registers according to their class, in the order shown below. For example, the first 32-bit data argument is placed in AC0. The second 32-bit data argument is placed in AC1, and so on.
- Argument Class Assigned to Register(s)
- data pointer (16 or 23 bits) (X)AR0, (X)AR1, (X)AR2, (X)AR3,(X)AR4
- 16-bit data T0, T1, AR0, AR1, AR2, AR3, AR4
- 32-bit data or 40−bit data AC0, AC1, AC2
- The ARx registers overlap for data pointers and 16-bit data. If, for example, T0 and T1 hold 16-bit data arguments, and AR0 already holds a data pointer argument, a third 16-bit data argument would be placed in AR1. For an example, see the second prototype in Example 6−2. If there are no available registers of the appropriate type, the argument goes on the stack.
- Arguments passed on the stack are handled as follows. The stack is initially aligned to an even boundary. Then, each argument is aligned on the stack as appropriate for the argument’s type (even alignment for long, long long, float, double, code pointers, and large model data pointers; no alignment for int, short, char, ioport pointers, and small model data pointers). Padding is inserted as necessary to bring arguments to the correct alignment.
- Argument Class Assigned to Register(s)
- The child function will save all of the save-on-entry registers (T2, T3, AR5−AR7). However, the parent function must save the values of the other registers, if they are needed after the call, by pushing the values onto the stack.
- The parent calls the function.
- The parent collects the return value.
- Short data values are returned in T0.
- Long data values are returned in AC0.
- Data pointer values are returned in (X)AR0.
- If the child returns a structure, the structure is on the local stack in the space allocated as described in step 1.