1
0
mirror of https://github.com/deadw00d/AROS.git synced 2025-11-22 19:54:08 +00:00
Files
AROS-v0/arch/x86_64-all/ABI_SPECIFICATION

154 lines
8.6 KiB
Plaintext

Specification of AROS x86_64 ABIv11 calling conventions
=======================================================
1. Caller-side (regular)
1a. Variadic functions in STACKCALL
2. Library-side
3. Caller-side (base-relative)
4. Implementation notes
Caller-side (Regular caller: program or library storing called library base in variable (local, global, field of structure))
============================================================================================================================
Type of call How base is fetched at caller ==> How base and arguments are passed to library
REGCALL
inline
regular Passed to inline function as value of __LIB_LIBBASE R12 for base / SysV x86_64 ABI for arguments
defined by default to (LibBase) global or local variable.
(LibBase) can be re-defined by caller.
define
regular Passed to macro as value of __LIB_LIBBASE R12 for base / SysV x86_64 ABI for arguments
defined by default to (LibBase) global or local variable.
(LibBase) cab be re-defined by caller.
linklib
regular Fetched in stub function as value of __LIB_LIBBASE R12 for base / SysV x86_64 ABI for arguments
which is compiled as (LibBase) global
variable. Re-defining (LibBase) by caller has no effect, as
stub function is already compiled.
STACKCALL
linklib
non-varargs
regular Fetched in stub function as value of __LIB_LIBBASE R12 for base / SysV x86_64 ABI for arguments
which is compiled as (LibBase) global
variable. Re-defining (LibBase) by caller has no effect, as
stub function is already compiled.
varargs
regular Fetched by compiled-in reading of (LibBase) global variable. R12 for base / SysV x86_64 ABI for arguments
Re-defining (LibBase) by caller has no effect, as stub function is
already compiled.
unusedlibbase
regular Fetched by compiled-in reading of (LibBase) global variable. Base not passed / SysV x86_64 ABI for arguments
Re-defining (LibBase) by caller has no effect, as stub function is
already compiled.
Variadic functions in STACKCALL
===============================
It it possible for a library to expose a C variadic function (using ... as last argument) when using STACKCALL call type. As with other
STACKCALL functions, there is a stub function generated in a linklib. This stub loads library base to R12 and passes arguments from caller
to library function. In this case however the function is special and complicated.
SysV x86_64 ABI defines that certain number of arguments is passed via registers and remaining are passed via stack. For non-varargs
function it is possible to derive at compile-time how many arguments were passed via stack. For varargs functions, there is no such
possibility. The stub for varargs function needs to copy the callers stack to stub stack, however it does not have information of how much
stack to copy. Thus, by default it copies up to 16 quad words. This can cause that arguments become "lost" if varargs function call passes
more arguments. If this happens, the caller needs to change this default limit.
Changing the limit is being done by defining a global symbol like:
int __<function>_<LibBaseName>_stack_varargs_cnt = <number>;
Where <function> is name of function being called, <LibBaseName> is name of library base and <number> is number of arguments (even, larger
than 16). Example:
int __fprintf_CrtBase_stack_varargs_cnt = 18;
Library-side
============
How base is passed to library => Addition library stub logic => How base is made available in library functions
Type of library
SingleBase
REGCALL
any R12 None Passed to each function as explicit parameter
STACKCALL
normal R12 None Fetched in each function via
__aros_getbase_LibBase() reading R12
unusedlibbase Not passed None Not available in functions
PerOpenerBase
REGCALL
any R12 None Passed to each function as explicit parameter
STACKCALL
normal R12 None Fetched in each function via
__aros_getbase_LibBase() reading R12
unusedlibbase Not passed None Not available in functions
Caller-side (Base-relative caller: library handling called library base via AROS 'rellib' option)
=================================================================================================
Type of call How base is fetched at caller ==> How base and arguments are passed to library
REGCALL
inline
base-relative Disabled Disabled
define
base-relative Passed to macro as value of __LIB_LIBBASE R12 for base / SysV x86_64 ABI for arguments
defined by default as result of __aros_getoffsettable() offsetted
by __aros_rellib_offset_LibBase global constant. Caller must
implement or define __aros_getoffsettable() returning
caller's library base.
linklib
base-relative Fetched in stub function as value of __LIB_LIBBASE R12 for base / SysV x86_64 ABI for arguments
which is compiled as result of
__aros_getoffsettable() offsetted by __aros_rellib_offset_LibBase
global constant. Caller must implement __aros_getoffsettable()
returning caller's library base.
STACKCALL
linklib
non-varargs
base-relative Fetched in stub function as value of __LIB_LIBBASE R12 for base / SysV x86_64 ABI for arguments
which is compiled as result of
__aros_getoffsettable() offsetted by __aros_rellib_offset_LibBase
global constant. Caller must implement __aros_getoffsettable()
returning caller's library base.
varargs
base-relative Fetched in stub function as results of R12 for base / SysV x86_64 ABI for arguments
__aros_getoffsettable() offsetted by __aros_rellib_offset_LibBase
global constant. Caller must implement __aros_getoffsettable()
returning caller's library base.
unusedlibbase
base-relative Fetched in stub function as results of Base not passed / SysV x86_64 ABI for arguments
__aros_getoffsettable() offsetted by __aros_rellib_offset_LibBase
global constant. Caller must implement __aros_getoffsettable()
returning caller's library base.
Implementation notes
====================
In case of REGCALL inline and REGCALL define, call code is created during compilation of caller side code. This means we require a certain
amount of control over R12 register at that time. Prior to GCC 7, this was accomplished by declaring a global register variable. This was
guaranteeing that R12 will not be used for local variable operations between moment it was set to contain library base to the moment the
call instruction was issued.
Starting with GCC 7 this approach (which worked due to side effect) no longer works. In order to keep the call macros simple and don't
re-implement ABI in assembler code, GCC is now hardcoded to have R12 as fixed register. This in effect means that R12 is not going to be
allocated by GCC in any caller side code.
Not using R12 in caller side code is however NOT an ABI requirement. The only requirement is that R12 is used to pass base during call and
that R12 is a calle-saved register (as per SysV x86_64 ABI).