From ca8ff11e05c12837a14503bf980f3cd2e10502d7 Mon Sep 17 00:00:00 2001 From: Hesham Almatary Date: Tue, 25 Jul 2023 16:06:50 +0100 Subject: [PATCH] libsel4test: retain _test_type and _test_case unused attribute does not prevent the sections from being garbage-collected during link-time optimisation. This may trigger undefined references errors to [__start|__stop]_test_case symbols that are expected to be emitted by the linker anyway. Adding "retain" attribute makes sure that the section and its associated symbols are kept regardless of linker's garbage collection. Another fix could be adding "nostart-stop-gc" to the linker flags, but since it is only one section (_test_case) where its __start/__stop symbols are references, adding retain to it makes more sense. This additional functionality requires binutils version 2.36 or later. Sponsored by: DARPA. Signed-off-by: Hesham Almatary --- libsel4test/include/sel4test/test.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/libsel4test/include/sel4test/test.h b/libsel4test/include/sel4test/test.h index 86522e582..7259bef76 100644 --- a/libsel4test/include/sel4test/test.h +++ b/libsel4test/include/sel4test/test.h @@ -98,6 +98,18 @@ typedef struct test_type { /* Declare a test type. * For now, we put the test types in a separate elf section. */ +#if defined(__has_attribute) && __has_attribute(retain) +#define DEFINE_TEST_TYPE(_name, _id, _set_up_test_type, _tear_down_test_type, _set_up, _tear_down, _run_test) \ + __attribute__((used,retain)) __attribute__((section("_test_type"))) struct test_type TEST_TYPE_ ##_name = { \ + .name = #_name, \ + .id = _id, \ + .set_up_test_type = _set_up_test_type, \ + .tear_down_test_type = _tear_down_test_type, \ + .set_up = _set_up, \ + .tear_down = _tear_down, \ + .run_test = _run_test, \ +}; +#else #define DEFINE_TEST_TYPE(_name, _id, _set_up_test_type, _tear_down_test_type, _set_up, _tear_down, _run_test) \ __attribute__((used)) __attribute__((section("_test_type"))) struct test_type TEST_TYPE_ ##_name = { \ .name = #_name, \ @@ -108,6 +120,7 @@ typedef struct test_type { .tear_down = _tear_down, \ .run_test = _run_test, \ }; +#endif /* Represents a single testcase. * Because this struct is used to declare variables that get @@ -133,6 +146,16 @@ typedef struct testcase ALIGN(sizeof(struct testcase)) testcase_t; * C99 style (name = _name, desc = _desc, func = _func...) to make sure * that it is accepted by C++ compilers. */ +#if defined(__has_attribute) && __has_attribute(retain) +#define DEFINE_TEST_WITH_TYPE(_name, _description, _function, _test_type, _enabled) \ + __attribute__((used,retain)) __attribute__((section("_test_case"))) struct testcase TEST_ ## _name = { \ + #_name, \ + _description, \ + (test_fn)_function, \ + _test_type, \ + _enabled, \ +}; +#else #define DEFINE_TEST_WITH_TYPE(_name, _description, _function, _test_type, _enabled) \ __attribute__((used)) __attribute__((section("_test_case"))) struct testcase TEST_ ## _name = { \ #_name, \ @@ -141,6 +164,7 @@ typedef struct testcase ALIGN(sizeof(struct testcase)) testcase_t; _test_type, \ _enabled, \ }; +#endif #define DEFINE_TEST(_name, _description, _function, _enabled) DEFINE_TEST_WITH_TYPE(_name, _description, _function, BASIC, _enabled)