mirror of
https://github.com/deadw00d/AROS.git
synced 2025-11-22 19:54:08 +00:00
154 lines
8.6 KiB
Plaintext
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).
|