https://m680x0.github.io/doc/abi.html
Skip links
* Skip to primary navigation
* Skip to content
* Skip to footer
M68k LLVM
* Documentation
* Blog
* Support Us
* About
Toggle menu
[ ] Toggle Menu
* Getting Started
+ How to Build M68k LLVM
+ Cross-Compiling M68k Binaries
* M68k Resources
+ Official Documents / References
+ Applicatoin Binary Interface (ABI)
M68k Application Binary Interface (ABI)
On this page
* Variants of ABIs
* Data Representations
+ Scalar Types
+ Aggregate Types
+ Stack Alignment
* Calling Convention
+ Stack Frame
+ Function Arguments
+ Return Values
Variants of ABIs
In this document, we're covering two variants of M68k ABIs:
1. Linux/GCC ABI: The default ABI used by GCC on Linux. It is
backward-compatible with many legacy compilers' ABIs, such as Sun
PCC. Yet it lacks formal documentations. This is currently the
only ABI implemented by M68k LLVM.
2. SystemV ABI: The default ABI used by UNIX systems. There is a
nice book documenting related details. Most of the contents in
this page are also adapted from it.
Data Representations
Scalar Types
Here are the sizes and alignments of all scalar types.
Alignment
Type C Type sizeof (bytes)
GCC ABI SysV
ABI
char / signed char / unsigned 1 1 1
char
short / signed short / unsigned 2 2 2
Integral short
int / signed int / unsigned int 4 2 4
long / signed long / unsigned 4 2 4
long
Pointer any-type * / any function pointer 4 2 4
type
Floating float 4 2 4
Point double 8 2 8
long double 16 2 8
The biggest difference between GCC and SysV ABIs is, of course, the
alignment. While SysV adopts natural alignment, GCC by default aligns
larger integer types on 16-bit boundaries.
Note that by using the -malign-int flag, which is not enabled by
default, GCC aligns int, long, float, double, and long double on
32-bit boundaries.
Another GCC-specific trick is the -mshort flag, which considers int
to be 16 bits.
Aggregate Types
Here are the rules to determine the layout and alignment of an
aggregate type (for example, struct or union):
* The alignment of an aggregate type is the maximum alignment of
its element types.
* Each member will be placed at the lowest offset while respecting
to its member type alignment. Internal paddings will be added if
needed.
* The size of an aggregate-type instance should be the multiple of
its alignment. Tail paddings will be added if needed.
Stack Alignment
There is a difference between GCC and SysV ABI on stack alignment: By
default, GCC aligns stack data on 16-bit boundaries, whereas SysV
uses 32-bit alignment.
Calling Convention
In this section, we're going to talk about the standard calling
convention used by M68k. It is splitted into three sub-sections:
Stack frame layout, passing function arguments, and handling return
values.
Stack Frame
The diagram below shows a typical M68k stack frame: [m68k-stack]
Usually, people use special instructions to setup a new stack frame.
For instance, JSR pushes return address to the stack before jumping
to the destination while RTS helps you to restore the return address
upon returning from a function; LINK and UNLNK instructions can help
you to save and restore the frame pointer.
In addition to special registers like %fp and %sp, other register
usages also follow a certain convention.
Register Names Usage
%d0,%d1 Scratch registers. Caller-save
%a0,%a1
%d2 ~ %d7 Local (variable) registers. Callee-save
%a2 ~ %a5
%a6 (%fp) Frame pointer (if implemented)
%a7 (%sp) Stack pointer
%pc Program counter
%ccr Condition code register
For floating point unit, which is available after 68040 / 6881, here
is a list of floating point register usages:
Register Names Usage
%fp0, %fp1 Scratch registers. Caller-save
%fp2 ~ %fp7 Local (variable) registers. Callee-save
%fpcr Floating point control register
%fpsr Floating point status register
%fpiar Floating point instruction address register
Function Arguments
As illustrated in the previous diagram, incoming function arguments
are passed by stack. Since arguments are always aligned on 32-bit
boundaries, they can be accessed at the following memory address
(assuming frame pointer is implemented):
%fp + 8 + N * 4
where N is the index of the argument. For instance, the first
argument is at %fp + 8 and the second is at %fp + 12.
When passing an aggregate-type object, regardless of their original
type alignment, the object will be aligned on 32-bit boundaries.
Return Values
An integral return value is put in %d0, whereas a pointer return
value is put in %a0.
When it comes to returning an aggregate-type object, the object
should be stored in memory and its address will be put in:
* SysV ABI: %a0
* GCC ABI: %a1
Whether it's caller or callee's responsibility to allocate the space
remains unspecified.
* Feed
(c) 2022 M68k LLVM. Powered by Jekyll & Minimal Mistakes.