Skip to content

Commit 9e93d96

Browse files
committed
Expand va_list description
Explain how a varargs save area is constructed, and define the representation of a va_list and the operation of va_arg independently of the definition of va_start. Fixes #412. Signed-off-by: Stefan O'Rear <[email protected]>
1 parent aa4698a commit 9e93d96

File tree

1 file changed

+30
-7
lines changed

1 file changed

+30
-7
lines changed

riscv-cc.adoc

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ contents of any fixed registers like `gp` and `tp` never change,
170170
NOTE: Calling convention for big-endian is *NOT* included in this specification
171171
yet, we intend to define that in future version of this specification.
172172

173+
[#integer-cc]
173174
=== Integer Calling Convention
174175

175176
The base integer calling convention provides eight argument registers,
@@ -655,13 +656,35 @@ purposes of data races.
655656

656657
=== va_list, va_start, and va_arg
657658

658-
The `va_list` type is `void*`. A callee with variadic arguments is responsible
659-
for copying the contents of registers used to pass variadic arguments to the
660-
vararg save area, which must be contiguous with arguments passed on the stack.
661-
The `va_start` macro initializes its `va_list` argument to point to the start
662-
of the vararg save area. The `va_arg` macro will increment its `va_list`
663-
argument according to the size of the given type, taking into account the
664-
rules about 2×XLEN aligned arguments being passed in "aligned" register pairs.
659+
The `va_list` type has the same representation as `void*` and points to a
660+
sequence of zero or more arguments with preceding padding for alignment,
661+
formatted and aligned as variadic arguments passed on the stack according to
662+
the integer calling convention (<<integer-cc>>). All standard calling conventions use the
663+
same representation for variadic arguments to allow `va_list` types to be
664+
shared between them.
665+
666+
The `va_start` macro in a function initializes its `va_list` argument to point
667+
to the first address at which a variadic argument could be passed to the
668+
function. If all integer argument registers are used for named formal
669+
arguments, the first variadic argument will have been passed on the stack by
670+
the caller, and the `va_list` can point to the address immediately after the
671+
last named argument passed on the stack, or the `sp` value on entry if no named
672+
arguments were passed on the stack. If some integer argument registers were not
673+
used for named formal arguments, then the first variadic argument may have been
674+
passed in a register. The function is then expected to construct a _varargs
675+
save area_ immediately below the entry `sp` and fill it with the entry values
676+
of all integer argument registers not used for named arguments, in sequence.
677+
The `va_list` value can then be initialized to the start of the varargs save
678+
area, and it will iterate through any variadic arguments passed via registers
679+
before continuing to variadic arguments passed on the stack, if any.
680+
681+
The `va_arg` macro will align its `va_list` argument, fetch a value, and
682+
increment the `va_list` according to the alignment and size of a variadic
683+
argument of the given type, which may not be the same as the alignment and size
684+
of the given type in memory. If the type is passed by reference, the size and
685+
alignment used will be those of a pointer, and the fetched pointer will be used
686+
as the address of the actual argument. The `va_copy` macro is a single pointer
687+
copy and the `va_end` macro performs no operation.
665688

666689
=== Vector type sizes and alignments
667690

0 commit comments

Comments
 (0)