summary refs log tree commit diff
path: root/test/vararg1.ssa
diff options
context:
space:
mode:
authorMichael Forney <mforney@mforney.org>2021-09-04 17:23:54 -0700
committerQuentin Carbonneaux <quentin@c9x.me>2021-09-07 08:31:48 +0200
commit6a69210b0faf33ad4feb6adc97d094022c520978 (patch)
tree1e1902fd35d5dffa34eda6be15f9dc822ba74ec1 /test/vararg1.ssa
parent649a546d702b41474fe76e9c779086cc8d35f3d2 (diff)
downloadroux-6a69210b0faf33ad4feb6adc97d094022c520978.tar.gz
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$
Diffstat (limited to 'test/vararg1.ssa')
-rw-r--r--test/vararg1.ssa7
1 files changed, 6 insertions, 1 deletions
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 <stdarg.h>
+# #include <stdio.h>
 # 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));
 # }