riscv-non-isa / riscv-elf-psabi-doc

A RISC-V ELF psABI Document
https://jira.riscv.org/browse/RVG-4
Creative Commons Attribution 4.0 International
691 stars 163 forks source link

Calling convention description of va_list et al. are unclear #412

Closed PerMildner closed 6 months ago

PerMildner commented 10 months ago

https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc#va_list-va_start-and-va_arg says:

A callee with variadic arguments is responsible for copying the contents of registers used to pass variadic arguments to the vararg save area, which must be contiguous with arguments passed on the stack. The va_start macro initializes its va_list argument to point to the start of the vararg save area. The va_arg macro will increment its va_list argument according to the size of the given type, taking into account the rules about 2×XLEN aligned arguments being passed in "aligned" register pairs.

The "vararg save area" does not seem to be defined or mentioned elsewhere.

It is not clear to me, from the quote, how the layout of the vararg save area is affected by the the use of '"aligned" register pairs'. I would expect va_arg to operate solely against an in-memory "vararg save area" and thus not need to know or care about register placement details.

So, perhaps some reference or details would be good?

jrtc27 commented 10 months ago

It is defined there. You save all the remaining GPRs to the region of memory that is in your stack frame and contiguous with the arguments passed on the stack, i.e. the top of your stack frame. That region of memory is the vararg save area.

The concept of aligned register pairs comes after that definition and does not affect va_start. It is in the part that defines how va_arg operates on that region of memory. That rule exists to allow you to not have to special-case whether a value was passed in a register or on the stack, since it makes the vararg save area look identical to how values are passed on the stack. Therefore the approach here is "spill it all to memory and treat it like it was all passed on the stack". Compilers are free to optimise and extract directly from registers if they wish, this just governs the ABI-visible behaviour of what a va_list is (a pointer) and points to (a single block of argument memory).

PerMildner commented 10 months ago

Thanks for the clarification. You are saying the quoted text is the definition of the "vararg save area", right? I did not realize that.

My other point, about "aligned" register pairs: You say "That rule exists to allow you to not have to special-case whether a value was passed in a register or on the stack, since it makes the vararg save area look identical to how values are passed on the stack." but if I (referring to the implementation of va_arg macro, I assume) do not need to care about whether the value was passed in register or memory (stack), I do not understand the 'The va_arg macro will increment ... taking into account the rules about ... arguments being passed in "aligned" register pairs.' which sounds like you (i.e., the implementation of va_arg) do need to care about details about how arguments are passed in registers.