Sujet : Re: Calling conventions (particularly 32-bit ARM)
De : theom+news (at) *nospam* chiark.greenend.org.uk (Theo)
Groupes : comp.archDate : 06. Jan 2025, 16:23:40
Autres entêtes
Organisation : University of Cambridge, England
Message-ID : <ySw*F1V3z@news.chiark.greenend.org.uk>
References : 1
User-Agent : tin/1.8.3-20070201 ("Scotasay") (UNIX) (Linux/5.10.0-28-amd64 (x86_64))
David Brown <
david.brown@hesbynett.no> wrote:
The big problem I see is the registers used for returning values from
functions. R0-R3 can all be used for passing arguments to functions, as
32-bit (or smaller) values, pointers, in pairs as 64-bit values, and as
parts of structs.
But the ABI only allows returning a single 32-bit value in R0, or a
scalar 64-bit value in R0:R1. If a function returns a non-scalar that
is larger than 32-bit, the caller has to allocate space on the stack for
the return type and pass a pointer to that space in R0.
According to EABI, it's also possible to return a 128 bit vector in R0-3:
https://github.com/ARM-software/abi-aa/blob/main/aapcs32/aapcs32.rst#result-returnTo my mind, this is massively inefficient, especially when using structs
that are made up of two 32-bit parts.
Is there any good reason why the ABI is designed with such limited
register usage for returns? Newer ABIs like RISC-V 32-bit and x86_64
can at least use two registers for return values. Modern compilers are
quite happy breaking structs into parts in individual registers - it's a
/long/ time since they insisted that structs occupied a contiguous block
of memory. Can anyone give me an explanation why return types can't
simply use all the same registers that are available for argument passing?
The 'composite type' return value, where a pointer is passed in as the first
argument to the function and a struct at that pointer is filled in with the
return values, has existed since the first ARM ABI - APCS-R:
http://www.riscos.com/support/developers/dde/appf.htmlThat dates from the mid 1980s before 'modern compilers', and I'm guessing
that has stuck around. A lot of early ARM code was in assembler. The
original ARMCC was good but fairly basic - GCC didn't support ARM until
about 1993.
[*] technically APCS-R was the second ARM ABI, APCS-A was the first:
https://heyrick.eu/assembler/apcsintro.htmlbut I don't think return value handling was any different.
Are there good technical reasons for the conventions on 32-bit ARM? Or
is this all just historical from the days when everything was an "int"
and that's all anyone ever returned from functions?
Probably the latter. Also that AArch64 was an opportunity to throw all this
stuff away and start again, with a much richer calling convention:
https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst#result-returnbut obviously that's no help to the microcontroller folks. At this stage, a
change of calling convention might be fairly big ask.
Theo