Add regression 1023 (ELF initialization via .init_array)

Adds a test case for the ELF initialization functions (.init_array
section).

Signed-off-by: Jerome Forissier <jerome@forissier.org>
Reviewed-by: Jens Wiklander <jens.wiklander@linaro.org>
diff --git a/host/xtest/regression_1000.c b/host/xtest/regression_1000.c
index fbc468e..8f31cc2 100644
--- a/host/xtest/regression_1000.c
+++ b/host/xtest/regression_1000.c
@@ -1757,3 +1757,54 @@
 }
 ADBG_CASE_DEFINE(regression, 1022, xtest_tee_test_1022,
 		"Test dlopen()/dlsym()/dlclose() API");
+
+/*
+ * Testing the ELF initialization (.init_array)
+ *
+ * - The TA has a global variable which can also be accessed by the two shared
+ *   libraries os_test_lib (linked with the TA) and os_test_lib_dl (loaded via
+ *   dlopen())
+ * - The TA and both libraries have initialization functions (declared with the
+ *   "constructor" attribute) which perform the following:
+ *     * The TA multiplies by 10 then adds 1
+ *     * os_test_lib multiplies by 10 then adds 2
+ *     * os_test_lib_dl multiplies by 10 then adds 3
+ * By testing the variable value we make sure the initializations occurred in
+ * the correct order.
+ */
+static void xtest_tee_test_1023(ADBG_Case_t *c)
+{
+	TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
+	TEEC_Session session = { 0 };
+	uint32_t ret_orig = 0;
+
+	op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_OUTPUT, TEEC_NONE,
+					 TEEC_NONE, TEEC_NONE);
+
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c,
+			xtest_teec_open_session(&session, &os_test_ta_uuid,
+				NULL, &ret_orig)))
+		return;
+
+	(void)ADBG_EXPECT_TEEC_SUCCESS(c,
+		TEEC_InvokeCommand(&session, TA_OS_TEST_CMD_GET_GLOBAL_VAR, &op,
+				   &ret_orig));
+
+	/* Expected: initialization of os_test_lib, then TA */
+	(void)ADBG_EXPECT_COMPARE_SIGNED(c, op.params[0].value.a, ==, 21);
+
+	(void)ADBG_EXPECT_TEEC_SUCCESS(c,
+		TEEC_InvokeCommand(&session, TA_OS_TEST_CMD_CALL_LIB_DL, NULL,
+				   &ret_orig));
+
+	(void)ADBG_EXPECT_TEEC_SUCCESS(c,
+		TEEC_InvokeCommand(&session, TA_OS_TEST_CMD_GET_GLOBAL_VAR, &op,
+				   &ret_orig));
+
+	/* Expected: initialization of os_test_lib_dl */
+	(void)ADBG_EXPECT_COMPARE_SIGNED(c, op.params[0].value.a, ==, 213);
+
+	TEEC_CloseSession(&session);
+}
+ADBG_CASE_DEFINE(regression, 1023, xtest_tee_test_1023,
+		"Test ELF initialization (.init_array)");
diff --git a/ta/os_test/include/os_test.h b/ta/os_test/include/os_test.h
index 708d80f..a675b5c 100644
--- a/ta/os_test/include/os_test.h
+++ b/ta/os_test/include/os_test.h
@@ -46,5 +46,6 @@
 TEE_Result ta_entry_call_lib_panic(uint32_t param_types, TEE_Param params[4]);
 TEE_Result ta_entry_call_lib_dl(uint32_t param_types, TEE_Param params[4]);
 TEE_Result ta_entry_call_lib_dl_panic(uint32_t param_types, TEE_Param params[4]);
+TEE_Result ta_entry_get_global_var(uint32_t param_types, TEE_Param params[4]);
 
 #endif /*OS_TEST_H */
diff --git a/ta/os_test/include/ta_os_test.h b/ta/os_test/include/ta_os_test.h
index 6a15128..0180539 100644
--- a/ta/os_test/include/ta_os_test.h
+++ b/ta/os_test/include/ta_os_test.h
@@ -48,5 +48,6 @@
 #define TA_OS_TEST_CMD_CALL_LIB_PANIC       15
 #define TA_OS_TEST_CMD_CALL_LIB_DL          16
 #define TA_OS_TEST_CMD_CALL_LIB_DL_PANIC    17
+#define TA_OS_TEST_CMD_GET_GLOBAL_VAR       18
 
 #endif /*TA_OS_TEST_H */
diff --git a/ta/os_test/os_test.c b/ta/os_test/os_test.c
index 1409470..7cc7088 100644
--- a/ta/os_test/os_test.c
+++ b/ta/os_test/os_test.c
@@ -1166,3 +1166,27 @@
 	dlclose(handle);
 	return res;
 }
+
+/* ELF initialization/finalization test */
+
+int os_test_global;
+
+static void __attribute__((constructor)) os_test_init(void)
+{
+	os_test_global *= 10;
+	os_test_global += 1;
+	DMSG("os_test_global=%d", os_test_global);
+}
+
+TEE_Result ta_entry_get_global_var(uint32_t param_types, TEE_Param params[4])
+{
+	if (param_types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_OUTPUT,
+					   TEE_PARAM_TYPE_NONE,
+					   TEE_PARAM_TYPE_NONE,
+					   TEE_PARAM_TYPE_NONE))
+		return TEE_ERROR_BAD_PARAMETERS;
+
+	params[0].value.a = os_test_global;
+
+	return TEE_SUCCESS;
+}
diff --git a/ta/os_test/ta_entry.c b/ta/os_test/ta_entry.c
index 52c378e..f47abee 100644
--- a/ta/os_test/ta_entry.c
+++ b/ta/os_test/ta_entry.c
@@ -121,6 +121,9 @@
 	case TA_OS_TEST_CMD_CALL_LIB_DL_PANIC:
 		return ta_entry_call_lib_dl_panic(nParamTypes, pParams);
 
+	case TA_OS_TEST_CMD_GET_GLOBAL_VAR:
+		return ta_entry_get_global_var(nParamTypes, pParams);
+
 	default:
 		return TEE_ERROR_BAD_PARAMETERS;
 	}
diff --git a/ta/os_test_lib/os_test_lib.c b/ta/os_test_lib/os_test_lib.c
index c97a039..f5c8127 100644
--- a/ta/os_test_lib/os_test_lib.c
+++ b/ta/os_test_lib/os_test_lib.c
@@ -5,6 +5,16 @@
 
 #include "os_test_lib.h"
 #include <tee_internal_api.h>
+#include <trace.h>
+
+extern int os_test_global;
+
+static void __attribute__((constructor)) os_test_shlib_init(void)
+{
+	os_test_global *= 10;
+	os_test_global += 2;
+	DMSG("os_test_global=%d", os_test_global);
+}
 
 int os_test_shlib_add(int a, int b)
 {
diff --git a/ta/os_test_lib_dl/os_test_lib_dl.c b/ta/os_test_lib_dl/os_test_lib_dl.c
index d08318e..5e90c42 100644
--- a/ta/os_test_lib_dl/os_test_lib_dl.c
+++ b/ta/os_test_lib_dl/os_test_lib_dl.c
@@ -5,6 +5,16 @@
 
 #include <os_test_lib_dl.h>
 #include <tee_internal_api.h>
+#include <trace.h>
+
+extern int os_test_global;
+
+static void __attribute__((constructor)) os_test_shlib_dl_init(void)
+{
+	os_test_global *= 10;
+	os_test_global += 3;
+	DMSG("os_test_global=%d", os_test_global);
+}
 
 int os_test_shlib_dl_add(int a, int b)
 {