SH Application Binary Interface for GCC

Glossary

Aggregate: struct and union in C.

Scalar: antonym of aggregate, i.e., as char, short, and int.

Frame: stack space pushed for a function invocation.

Byte Ordering:

The SH architecture supports both big-endian byte ordering and little-endian byte ordering. Big-endian code and little-endian code may not be mixed in the same program.

Use of floating-point unit:

Code may be created either to use the floating-point unit, or to perform all floating-point operations in software. Code that uses the floating-point unit is said to use the fpu model, code that performs all floating-point operations in software is said to use the nofpu model. The choice of floating-point model affects the way that function arguments and results are passed.

Fpu model code and nofpu model code may not, in general, be mixed in the same program.

Stack Layout:

Data type sizes and alignments

The following table shows the size and alignment for all data types:

Type Size (bytes) Alignment (bytes)
char 1 byte 1 byte
short 2 byte 2 byte
int 4 byte 4 byte
long 4 byte 4 byte
long long 8 byte 4 byte
float 4 byte 4 byte
Double#1 8 byte 4 byte
long Double 8 byte 4 byte
Pointer 4 byte 4 byte

#1 Size of Double is 4 bytes in SH3e.

Register Usage:

The registers and there usage is given below:
R0-R1:         Return value, caller saves
R2-R3:         Scratch, Caller saves
R2:               Large struct return address, caller save (when –mhitachi is not specified)
R4-R7:         Parameter passing, caller saves
R8-R13:       Callee Saves
R14:             Frame Pointer, FP, callee saves
R15:             Stack Pointer, SP, callee saves
FR0-FR3:     Return value, caller saves
FR4-FR11:   Parameter passing, caller saves
FR12-FR15: Callee saves
MACH:        Caller saves
MACL:         Caller saves
(If –mhitachi option is used MAC registers are Callee save.)

PR:                Linkage register(saves the subroutine return address), caller saves
SR:                Status register
GBR:             Reserved
VBR:             Reserved

Frame Pointer

R14 is used as the frame pointer. -fomit-frame-pointer can be used to eliminate the use of the frame pointer in favor of the stack pointer.

Function linkage and parameter passing
Parameter Passing
Registers R4-R7, FR4-FR11, and stack are used for parameter passing.

a) The first four arguments are passed in registers R4 through R7. The floating-point arguments are passed in fr4 through fr11. All the remaining arguments are pushed onto the stack, last to first, so that the lowest numbered argument not passed in a register is at the lowest address in the stack.

b) These registers are always filled in SH3. For e.g. if you have function

foo( int a, int b, int c, long long d )

a,b,c are passed in r4,r5,r6 respectively but d is passed partly in r7 and partly on stack.

But for SH3e and SH4 the entire argument is passed on stack. Here the parameter d will be passed entirely on stack.

c) If –mhitachi option is used the aggregate types are passed using stack. For e.g., in the following code the members of structure s in the foo(s) function call are passed using stack. This would have been passed using registers without the option.

typedef struct _S { int a; }S;
S s ;

S foo ( S s )
{
       return s ;
}

void bar()
{
       s = foo( s) ;
}

Every stack push is rounded to a multiple 4 bytes. If the size of a value pushed onto the stack is different from the size of an actual push, padding is added downward. For example, if 2 bytes of data, 0x1234, are to be pushed onto the stack, 4 bytes are pushed like so:

sp + 3 0x34

sp + 2 0x12

sp + 1 padding (unknown value)

sp + 0 padding (unknown value)  

d) Extension of arguments: when you pass a char or short to a func or get a return value the tool chain does not sign extend any values. It remains as it is. 

Function Value

The scalar function value no larger than 4 bytes in size is returned in R0 and FR0 and values no larger than 8 bytes are returned in R0 and R1.

If R0 and R1 are used to return the function value, R0 contains the most significant part and R1 contains the least significant part for big-endian mode and vice-versa for little-endian mode.

For all other types, the function value is always returned in memory. Specifically, the caller allocates an instance of the aggregate type and passes a pointer to the instance as an invisible argument. The caller stores the function value into the memory location pointed to by the invisible pointer.

Bit-Field

A bit-field is allocated within a storage unit whose alignment and size are the same as the alignment and size of the underlying type of the bit-field. The bit-field must reside entirely within this storage unit: a bit-field never straddles the natural boundary of the underlying type.

In the little-endian ABI, bit-fields are allocated from right to left (least to most significant) within a storage unit. In the big-endian ABI, bit-fields are allocated from left to right (most to least significant) within a storage unit.

A bit-field shares a storage unit with the previous structure member if there is sufficient space within the storage unit.

Structure Alignment

Every structure member is aligned to 4 bytes unless __attribute__ ((packed)) is used.