From 6a69210b0faf33ad4feb6adc97d094022c520978 Mon Sep 17 00:00:00 2001 From: Michael Forney Date: Sat, 4 Sep 2021 17:23:54 -0700 Subject: test: use architecture-neutral wrapper for calling vprintf Different architectures use different types for va_list: x86_64 uses an 1-length array of struct type[0]: typedef struct { unsigned int gp_offset; unsigned int fp_offset; void *overflow_arg_area; void *reg_save_area; } va_list[1]; aarch64 uses a struct type[1] typedef struct { void *__stack; void *__gr_top; void *__vr_top; int __gr_offs; int __vr_offs; } va_list; Consequently, C functions which takes a va_list as an argument, such as vprintf, may pass va_list in different ways depending on the architecture. On x86_64, va_list is an array type, so parameter decays to a pointer and passing the address of the va_list is correct. On aarch64, the va_list struct is passed by value, but since it is larger than 16 bytes, the parameter is replaced with a pointer to caller-allocated memory. Thus, passing the address as an l argument happens to work. However, this pattern of passing the address of the va_list to vprintf doesn't extend to other architectures. On riscv64, va_list is defined as typedef void *va_list; which is *not* passed by reference. This means that tests that call vprintf using the address of a va_list (vararg1 and vararg2) will not work on riscv. To fix this while keeping the tests architecture-neutral, add a small wrapper function to the driver which takes a va_list *, and let the C compiler deal with the details of passing va_list by value. [0] https://c9x.me/compile/bib/abi-x64.pdf#figure.3.34 [1] https://c9x.me/compile/bib/abi-arm64.pdf#%5B%7B%22num%22%3A63%2C%22gen%22%3A0%7D%2C%7B%22name%22%3A%22XYZ%22%7D%2C52%2C757%2C0%5D [2] https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc#va_list-va_start-and-va_arg$ --- test/vararg1.ssa | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'test/vararg1.ssa') diff --git a/test/vararg1.ssa b/test/vararg1.ssa index 393743c..3b33890 100644 --- a/test/vararg1.ssa +++ b/test/vararg1.ssa @@ -13,13 +13,18 @@ function w $g(l %fmt, ...) { @start %vp =l alloc8 32 vastart %vp - %r =w call $vprintf(l %fmt, l %vp) + %r =w call $print(l %fmt, l %vp) ret %r } # >>> driver +# #include +# #include # extern double f(int, ...); # extern int g(char *, ...); +# int print(const char *fmt, va_list *ap) { +# return vprintf(fmt, *ap); +# } # int main() { # g("Hell%c %s %g!\n", 'o', "world", f(42, "x", 42.0)); # } -- cgit 1.4.1