Personal tools
PGI Workstation User's Guide - A Run-time Environment
A Run-time Environment
- A.1 Programming Model
- A.2 Function Calling Sequence
- A.3 Functions Returning Scalars or No Value
- A.4 Integral and Pointer Arguments
- A.5 Floating-Point Arguments
- A.6 Structure and Union Arguments
This appendix describes the programming model supported for compiler code generation, including register conventions, and common object file formats.
A.1 Programming Model
This section defines compiler and assembly language conventions for the use of certain aspects of the processor. These standards must be followed to guarantee that compilers, applications programs, and operating systems written by different people and organizations will work together. The conventions supported by the PGCC ANSI C compiler implement the application binary interface (ABI) as defined in the System V Application Binary Interface: Intel Processor Supplement and the System V Application Binary Interface, listed in the section "Related Publications," in the Preface.
A.2 Function Calling Sequence
This section describes the standard function calling sequence, including the stack frame, register usage, and parameter passing.
Register Assignment
Table A-1 defines the standard for register allocation. The Intel Architecture (IA) provides a number of registers. All the integer registers and all the floating-point registers are global to all procedures in a running program.
Table A-1 Register Allocation
Type
|
Name
|
Purpose
|
---|---|---|
General |
%eax |
integer return value |
%edx |
dividend register (for divide operations) | |
%ecx |
count register (shift and string operations) | |
%ebx |
local register variable | |
%ebp |
stack frame pointer | |
%esi |
local register variable | |
%edi |
local register variable | |
%esp |
stack pointer | |
Floating-point |
%st(0) |
floating-point stack top, return value |
%st(1) |
floating-point next to stack top | |
%st(...) |
||
%st(7) |
floating-point stack bottom |
In addition to the registers, each function has a frame on the run-time stack. This stack grows downward from high addresses. Table A-2 shows the stack frame organization.
Table A-2 Standard Stack Frame
Position
|
Contents
|
Frame
|
---|---|---|
4n+8 (%ebp) |
argument word n |
previous |
8 (%ebp) |
argument word 0 |
|
4 (%ebp) |
return address |
|
0 (%ebp) |
caller's %ebp |
current |
-4 (%ebp) |
n bytes of local |
|
-n (%ebp) |
variables and temps |
Several key points concerning the stack frame:
- The stack is kept double word aligned for best performance.
- Argument words are pushed onto the stack in reverse order (i.e. the rightmost argument in a C call syntax has the highest address) A dummy word may be pushed ahead of the rightmost argument in order to preserve doubleword alignment. All incoming arguments appear on the stack, residing in the stack frame of the caller.
- An argument's size is increased, if necessary, to make it a multiple of words. This may require tail padding, depending on the size of the argument.
All registers on a IA system are global and thus visible to both a calling and a called function. Registers %ebp, %ebx, %edi, %esi, and %esp belong to the calling function. In other words, a called function must preserve these registers' values for its caller. Remaining registers belong to the called function. If a calling function wants to preserve such a register value across a function call, it must save a value in its local stack frame.
Some registers have assigned roles in the standard calling sequence:
- %esp
- The stack pointer holds the limit of the current stack frame, which is the address of the stack's bottom-most, valid word. At all times, the stack pointer should point to a word-aligned area.
- %ebp
- The frame pointer holds a base address for the current stack frame. Consequently, a function has registers pointing to both ends of its frame. Incoming arguments reside the previous frame, referenced as positive offsets from %ebp, while local variables reside in the current frame, referenced as negative offsets from %ebp. A function must preserve this register value for its caller.
- %eax
- Integral and pointer return values appear in %eax. A function that returns a struct or union value places the address of the result in %eax. Otherwise, this is a scratch register.
- %esi and %edi
- These local registers have no specified role in the standard calling sequence. Functions must preserve their values for the caller.
- %ecx and %edx
- Scratch registers have no specified role in the standard calling sequence. Functions do not have to preserve their values for the caller.
- %st(0)
- Floating-point return values appear on the top of the floating-point register stack; there is no difference in the representation of single or double-precision values in floating point registers. If the function does not return a floating point value, then this register must be empty.
- %st(1) through %st(7)
Floating point scratch registers have no specified role in the standard calling sequence. These registers must be empty before entry and upon exit from a function.- EFLAGS
- The flags register contains the system flags, such as the direction flag and the carry flag. The direction flag must be set to the "forward" (i.e. zero) direction before entry and upon exit from a function. Other user flags have no specified role in the standard calling sequence and are not reserved.
- Floating Point Control Word
The control word contains the floating-point flags, such as the rounding mode and exception masking. This register is initialized at process initialization time and its value must be preserved.
Signals can interrupt processes. Functions called during signal handling have no unusual restriction on their use of registers. Moreover, if a signal handling function returns, the process resumes its original execution path with registers restored to their original values. Thus, programs and compilers may freely use all registers without danger of signal handlers changing their values.
A.3 Functions Returning Scalars or No Value
A function that returns an integral or pointer value places its result in register %eax.
A function that returns a long long integer value places its result in the registers %edx and %eax. The most significant word is placed in %edx and the least significant word is placed in %eax.
A floating-point return value appears on the top of the fpu register stack. The caller must then remove the value from the fpu stack, even if it doesn't use the value. Failure of either side to meet its obligations leads to undefined program behavior. The standard calling sequence does not include any method to detect such failures nor to detect return value type mismatches. Therefore the user must declare all functions properly. There is no difference in the representation of single-, double- or extended-precision values in floating-point registers.
Functions that return no value (also called procedures or void functions) put no particular value in any register.
A call instruction pushes the address of the next instruction ( the return address) onto the stack. The return instruction pops the address off the stack and effectively continues execution at the next instruction after the call instruction. A function that returns a scalar or no value must preserve the caller's registers as described above. Additionally, the called function must remove the return address from the stack, leaving the stack pointer (%esp) with the value it had before the call instruction was executed.
Functions Returning Structures or Unions
If a function returns a structure of union, then the caller provides space for the return value and places its address on the stack as argument word zero. In effect, this address becomes a hidden first argument. Having the caller supply the return objects spaces allows re-entrancy.
A function that returns a structure or union also sets %eax to the value of the original address of the caller's area before it returns. Thus when the caller receives control again, the address of the returned object resides in register %eax and can be used to access the object. Both the calling and the called functions must cooperate to pass the return value successfully:
- The calling function must supply space for the return value and pass its address in the stack frame;
- The called function must use the address from the frame and copy the return value to the object so supplied;
- The called function must remove this address from the stack before returning.
Failure of either side to meet its obligation leads to undefined program behavior. The standard function calling sequence does not include any method to detect such failures nor to detect structure and union type mismatches. Therefore the user must declare the function properly.
Table A-3 illustrates the stack contents when the function receives control, after the call instruction, and when the calling function again receives control, after the ret instruction.
Table A-3 Stack Contents for Functions Returning struct/union
Position
|
After Call
|
After Return
|
Position
| |
---|---|---|---|---|
4n+8 (%esp) |
argument word n |
argument word n |
4n-4 (%esp) | |
8 (%esp) |
argument word 1 |
argument word 1 |
0 (%esp) | |
4 (%esp) |
value address |
undefined |
||
0 (%esp) |
return address |
The following sections of this appendix describe where arguments appear on the stack. The examples are written as if the function prologue described above had been used.
A.4 Integral and Pointer Arguments
As mentioned, a function receives all its arguments through the stack; the last argument is pushed first. In the standard calling sequence, the first argument is at offset 8 (%ebp), the second argument is at offset 12 (%ebp), etc. Functions pass all integer-valued arguments as words, expanding or padding signed or unsigned bytes and halfwords as needed.
Table A-4 Integral and Pointer Arguments
Call
|
Argument
|
Stack Address
|
---|---|---|
g(1, 2, 3, (void *)0); |
1 |
8 (%ebp) |
2 |
12 (%ebp) | |
3 |
16 (%ebp) | |
(void *) 0 |
20 (%ebp) |
A.5 Floating-Point Arguments
The stack also holds floating-point arguments: single-precision values use one word, and double-precision use two. The example below uses only double-precision arguments.
Table A-5 Floating-point Arguments
Call
|
Argument
|
Stack Address
|
---|---|---|
h(1.414, 1, 2.998e10); |
word 0, 1.414 |
8 (%ebp) |
word 1, 1.414 |
12 (%ebp) | |
1 |
16 (%ebp) | |
word 0 2.998e10 |
20 (%ebp) | |
word 1, 2.998e10 |
24 (%ebp) |
A.6 Structure and Union Arguments
As described in the data representation section, structures and unions can have byte, halfword, or word alignment, depending on the constituents. An argument's size is increased, if necessary, to make it a multiple of words. This may require tail padding, depending on the size of the argument. To ensure that data in the stack is properly aligned, the stack pointer should always point to a double word boundary. Structure and union arguments are pushed onto the stack in the same manner as integral arguments, described above. This provides call-by-value semantics, letting the called function modify its arguments without affecting the calling functions object.
Table A-6 Structure and Union Arguments
Call |
Argument |
Stack Address |
---|---|---|
i(1,s); |
1 |
8 (%ebp) |
word 0, s |
12 (%ebp) | |
word 1, s |
16 (%ebp) | |
... |
... |
Implementing a Stack
In general, compilers and programmers must maintain a software stack. Register %esp is the stack pointer. Register %esp is set by the operating system for the application when the program is started. The stack must be a grow-down stack.
A separate frame pointer enables calls to routines that change the stack pointer to allocate space on the stack at run-time (e.g. alloca). Some languages can also return values from a routine allocated on stack space below the original top-of-stack pointer. Such a routine prevents the calling function from using %esp-relative addressing to get at values on the stack. If the compiler does not call routines that leave %esp in an altered state when they return, a frame pointer is not needed and is not used if the compiler option -Mnoframe is specified.
Although not required, the stack should be kept aligned on 8-byte boundaries. Each routine should use stack space in multiples of 8 bytes. PGI's compilers allocate stack space in multiples of 8 bytes.
Variable Length Parameter Lists
Parameter passing in registers can handle a variable number of parameters. The C language uses a special method to access variable-count parameters. The stdarg.h and varargs.h files define several functions to access these parameters. A C routine with variable parameters must use the va_start macro to set up a data structure before the parameters can be used. The va_arg macro must be used to access the successive parameters.
C Parameter Conversion
In C, for a called prototyped function, the parameter type in the called function must match the argument type in the calling function. If the called function is not prototyped, the calling convention uses the types of the arguments but promotes char or short to int, and unsigned char or unsigned short to unsigned int and promotes float to double, unless you use the -Msingle option. For more information on the -Msingle option, refer to Chapter 7, Command-line Options. If the called function is prototyped, the unused bits of a register containing a char or short parameter are undefined and the called function must extend the sign of the unused bits when needed.
Calling Assembly Language Programs
/* File: testmain.c */
main()
{
long l_para1 = 0x3f800000;
float f_para2 = 1.0;
double d_para3 = 0.5;
float f_return;
extern float sum_3 (
long para1,
float para2,
double para3);
f_return = sum_3(l_para1, f_para2, d_para3);
printf("Parameter one, type long = %08x\n", l_para1);
printf("Parameter two, type float = %f\n", f_para2);
printf("Parameter three, type double = %g\n", d_para3);
printf("The sum after conversion = %f\n", f_return);
}
// File: sum_3.s
// Computes ( para1 + para2 ) + para3
/ PGC Rel 1.1 -opt 1
.align 4
.long .EN1-sum_3+0xc8000000
.text
.align 16
.globl sum
sum_3:
.EN1:
subl $12,%esp
movl %ebp,8(%esp)
leal 8(%esp),%ebp
fildl 8(%ebp)
fadds 12(%ebp)
faddl 16(%ebp)
fsts 12(%ebp)
fstps -4(%ebp)
flds -4(%ebp)
movl %ebp,%esp
popl %ebp
ret
.type sum_3,@function
sum_3,.-sum_3
Example A-1 C Program Calling an Assembly-language Routine
<< " border=0> > " border=0>