From d0467b19141f8c11fcf1e1d77dc1b4372b1c0a6e Mon Sep 17 00:00:00 2001 From: Scott Graham Date: Thu, 25 Jan 2024 11:47:14 -0800 Subject: [PATCH] Fix win abi bug causing stack dealignment for when passing struct by value --- src/codegen.in.c | 4 ++- test/substructs.c | 19 ++++++++++++++ test/update_structabi2.py | 52 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 test/substructs.c create mode 100644 test/update_structabi2.py diff --git a/src/codegen.in.c b/src/codegen.in.c index 0d834e8..99ea973 100644 --- a/src/codegen.in.c +++ b/src/codegen.in.c @@ -835,7 +835,9 @@ static int push_args_win(Node* node, int* by_ref_copies_size) { assert((*by_ref_copies_size == 0 && !has_by_ref_args) || (*by_ref_copies_size && has_by_ref_args)); - if ((C(depth) + stack + (*by_ref_copies_size / 8)) % 2 == 1) { + // Realign the stack to 16 bytes if rsp fiddling mucked it up. + size_t r11_push_size = has_by_ref_args ? 1 : 0; + if ((C(depth) + stack + (*by_ref_copies_size / 8) + r11_push_size) % 2 == 1) { ///| sub rsp, 8 C(depth)++; stack++; diff --git a/test/substructs.c b/test/substructs.c new file mode 100644 index 0000000..6e71075 --- /dev/null +++ b/test/substructs.c @@ -0,0 +1,19 @@ +#include "test.h" + +struct B { + int x; + int y; + int z; +}; + +void f(struct B b) { + ASSERT(10, b.x); + ASSERT(20, b.y); + ASSERT(30, b.z); +} + +int main(void) { + struct B b = {10, 20, 30}; + f(b); + return 0; +} diff --git a/test/update_structabi2.py b/test/update_structabi2.py new file mode 100644 index 0000000..39d7d9c --- /dev/null +++ b/test/update_structabi2.py @@ -0,0 +1,52 @@ +from test_helpers_for_update import * + +HOST = '''\ +#include + +struct B { + int x; + int y; + int z; +}; + +void test_f(struct B b) { + printf("%d %d %d\\n", b.x, b.y, b.z); +} +''' + +SRC = '''\ +#include + +struct B { + int x; + int y; + int z; +}; + +extern void test_f(struct B b); + +// This was causing stack un-alignment due to how struct copying was +// implemented in codegen. +int main(void) { + struct B b = {10, 20, 30}; + test_f(b); + printf("OK\\n"); + return 0; +} +''' + +# This is not really an "update" test, but because the update tests happen to +# build a separate host binary rather than using the standard dyibicc.exe, it +# gives us a way to have C code to call that's test-specific and compiled by +# the host compiler, rather than by ours. + +add_to_host(HOST); +add_host_helper_func("test_f") +include_path("../../test") + +initial({'main.c': SRC}) +update_ok() +expect(0) + +done() +