Skip to content
This repository was archived by the owner on Aug 2, 2019. It is now read-only.

Latest commit

 

History

History
117 lines (95 loc) · 6.34 KB

native-interface-x64-unix.rest

File metadata and controls

117 lines (95 loc) · 6.34 KB

AMD64 Unix Native Interface

This is the native interface for AMD64 on Unix-like operating systems.

Memory Layout

The memory layout of the native memory uses the System V Application Binary Interface for x86-64 (referred to as "the AMD64 ABI" from now on) as a reference. It is recommended that the Mu memory also use this memory layout, but is not required since the Mu memory it is never externally visible unless explicitly pinned.

Data in the native memory uses the sizes and alignments of types are listed in the following table. The unit of sizes and alignments is byte, which is 8 bits. All non-native-safe types have unspecified sizes and alignments.

Mapping between Mu and C types
Mu type C type Size Alignment
int<8> char 1 1
int<16> short 2 2
int<32> int 4 4
int<64> long, long long 8 8
float float 4 4
double double 8 8
vector<int<8> 4> __m128 16 16
vector<float 4> __m128 16 16
vector<double 2> __m128 16 16
uptr<T> T * 8 8
ufuncptr<sig> T (*) () 8 8
ref<T> N/A unspecified unspecified
iref<T> N/A unspecified unspecified
weakref<T> N/A unspecified unspecified
tagref64 N/A unspecified unspecified
funcref<sig> N/A unspecified unspecified
threadref N/A unspecified unspecified
stackref N/A unspecified unspecified
int<1> N/A unspecified unspecified
int<6> N/A unspecified unspecified
int<52> N/A unspecified unspecified
int<n> unspecified unspecified unspecified
vector<T n> unspecified unspecified unspecified

NOTE: Although int<1> is required and int<6> and int<52> are required when tagref64 is implemented, their memory layout is unspecified because memory access instructions LOAD, STORE, etc. are not required to support those types. It it not recommended to include those types in the memory because they may never be loaded or stored.

Although vectors of other lengths are not required by a Mu implementation, implementations are encouraged to support them in a way compatible with the AMD64 ABI.

The structure type struct<...> and the hybrid type hybrid<Fs V> is aligned to its most strictly aligned component. Each member is assigned to the lowest available offset with the appropriate alignment. This rule applies to hybrids as if the hybrid hybrid<Fs V> is a struct of fields Fs followed by a flexible array member (as in C99) V fam[];. Arrays array<T> use the same alignment as its elements.

NOTE: There is no union types in Mu. Arrays do not have special rules of 16-byte alignment as the AMD64 ABI does. Mu arrays must be declared as an array of vectors (such as array<vector<int<32> 4> 100>) to be eligible for vector access.

Both integers and floating point numbers are little-endian (lower bytes in lower addresses). Signed integers use the 2's complement representation. Elements with lower indexes in a vector is stored in lower addresses in the memory.

Calling Convention

The calling convention between Mu functions is implementation-defined.

The Default Calling Convention

The default calling convention, denoted by the #DEFAULT flag in the IR, follows the AMD64 ABI in register usage, stack frame structure, parameter passing and returning. The parameter types and the return types are mapped to C types according to the above table. Functions in this calling convention can return at most one value. As a special case, if the native function signature returns void, the corresponding Mu signature returns no values (...) -> (). Mu struct and array types are mapped to C structs of corresponding members. array cannot be the type of parameters or return values because C disallows this, but arrays within structs and pointers to arrays are is allowed.

Arguments and return values are passed in registers and the memory according to the AMD64 ABI, with the types of Mu arguments and the return type mapped to the corresponding C types.

NOTE: This is to say, C programs can call Mu functions with a "compatible" signature (that is, parameters and return values match the above table). Even if the signature is not "perfectly" matching (for example, an int/long is passed when a pointer is expected, Mu must still interpret the incoming arguments strictly according to the ABI, i.e. interpreting the integer value in the register as an address).

If a Mu function of signature sig is exposed with the default calling convention, the resulting value has ufuncptr<sig> type, i.e. it is a function pointer which can be called (by either Mu or native programs) with the default calling convention.

It has undefined behaviour when the native program attempts to unwind Mu frames.

NOTE: This means C longjmp and C++ exceptions must not go through Mu frames, but as long as they are handled above any Mu frames, it is safe.