[PATCH] score: Fix TLS support for some code models

Sebastian Huber sebastian.huber at embedded-brains.de
Thu Sep 14 06:59:00 UTC 2023


Store symbols with an arbitrary absolute address such as _TLS_Size,
_TLS_Alignment, _TLS_Data_size, and _TLS_BSS_size in an object to avoid issues
with some code models.

Update #4953.
---
 cpukit/include/rtems/score/tls.h  | 120 +++++++++++++++++-------------
 cpukit/score/src/tlsallocsize.c   |  43 +++++++++--
 testsuites/sptests/sptls01/init.c |   4 +-
 3 files changed, 108 insertions(+), 59 deletions(-)

diff --git a/cpukit/include/rtems/score/tls.h b/cpukit/include/rtems/score/tls.h
index fa3ee0afa2..8716c5230c 100644
--- a/cpukit/include/rtems/score/tls.h
+++ b/cpukit/include/rtems/score/tls.h
@@ -10,7 +10,7 @@
  */
 
 /*
- * Copyright (C) 2014, 2022 embedded brains GmbH & Co. KG
+ * Copyright (C) 2014, 2023 embedded brains GmbH & Co. KG
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -59,31 +59,51 @@ extern "C" {
  * @{
  */
 
-extern char _TLS_Data_begin[];
-
-extern char _TLS_Data_end[];
+/**
+ * @brief Represents the TLS configuration.
+ */
+typedef struct {
+  /**
+   * @brief This member is initialized to _TLS_Data_begin.
+   */
+  const char *data_begin;
 
-extern char _TLS_Data_size[];
+  /**
+   * @brief This member is initialized to _TLS_Data_size.
+   */
+  const char *data_size;
 
-extern char _TLS_BSS_begin[];
+  /**
+   * @brief This member is initialized to _TLS_BSS_begin.
+   */
+  const char *bss_begin;
 
-extern char _TLS_BSS_end[];
+  /**
+   * @brief This member is initialized to _TLS_BSS_size.
+   */
+  const char *bss_size;
 
-extern char _TLS_BSS_size[];
+  /**
+   * @brief This member is initialized to _TLS_Size.
+   */
+  const char *size;
 
-extern char _TLS_Size[];
+  /**
+   * @brief This member is initialized to _TLS_Alignment.
+   */
+  const char *alignment;
+} TLS_Configuration;
 
 /**
- * @brief The TLS section alignment.
+ * @brief Provides the TLS configuration.
  *
- * This symbol is provided by the linker command file as the maximum alignment
- * of the .tdata and .tbss sections.  The linker ensures that the first TLS
- * output section is aligned to the maximum alignment of all TLS output
- * sections, see function _bfd_elf_tls_setup() in bfd/elflink.c of the GNU
- * Binutils sources.  The linker command file must take into account the case
- * that the .tdata section is empty and the .tbss section is non-empty.
+ * Directly using symbols with an arbitrary absolute address such as
+ * _TLS_Alignment may not work with all code models (for example the AArch64
+ * tiny and small code models).  Store the addresses in a read-only object.
+ * Using the volatile qualifier ensures that the compiler actually loads the
+ * address from the object.
  */
-extern char _TLS_Alignment[];
+extern const volatile TLS_Configuration _TLS_Configuration;
 
 typedef struct {
   /*
@@ -115,39 +135,25 @@ typedef struct {
   uintptr_t offset;
 } TLS_Index;
 
-/**
- * @brief Gets the size of the thread-local storage data in bytes.
- *
- * @return Returns the size of the thread-local storage data in bytes.
- */
-static inline uintptr_t _TLS_Get_size( void )
-{
-  uintptr_t size;
-
-  /*
-   * We must be careful with using _TLS_Size here since this could lead GCC to
-   * assume that this symbol is not 0 and the tests for 0 will be optimized
-   * away.
-   */
-  size = (uintptr_t) _TLS_Size;
-  RTEMS_OBFUSCATE_VARIABLE( size );
-  return size;
-}
-
 /**
  * @brief Gets the size of the thread control block area in bytes.
  *
+ * @param config is the TLS configuration.
+ *
  * @return Returns the size of the thread control block area in bytes.
  */
-static inline uintptr_t _TLS_Get_thread_control_block_area_size( void )
+static inline uintptr_t _TLS_Get_thread_control_block_area_size(
+  const volatile TLS_Configuration *config
+)
 {
 #if CPU_THREAD_LOCAL_STORAGE_VARIANT == 11
   uintptr_t alignment;
 
-  alignment = (uintptr_t) _TLS_Alignment;
+  alignment = (uintptr_t) config->alignment;
 
   return RTEMS_ALIGN_UP( sizeof( TLS_Thread_control_block ), alignment );
 #else
+  (void) config;
   return sizeof( TLS_Thread_control_block );
 #endif
 }
@@ -163,17 +169,23 @@ uintptr_t _TLS_Get_allocation_size( void );
 /**
  * @brief Initializes the thread-local storage data.
  *
+ * @param config is the TLS configuration.
+ *
  * @param[out] tls_data is the thread-local storage data to initialize.
  */
-static inline void _TLS_Copy_and_clear( void *tls_data )
+static inline void _TLS_Copy_and_clear(
+  const volatile TLS_Configuration *config,
+  void                             *tls_data
+)
 {
-  tls_data = memcpy( tls_data, _TLS_Data_begin, (uintptr_t) _TLS_Data_size );
+  tls_data =
+    memcpy( tls_data, config->data_begin, (uintptr_t) config->data_size );
 
   memset(
     (char *) tls_data +
-      (uintptr_t) _TLS_BSS_begin - (uintptr_t) _TLS_Data_begin,
+      (uintptr_t) config->bss_begin - (uintptr_t) config->data_begin,
     0,
-    (uintptr_t) _TLS_BSS_size
+    (uintptr_t) config->bss_size
   );
 }
 
@@ -213,20 +225,22 @@ static inline void _TLS_Initialize_TCB_and_DTV(
  */
 static inline void *_TLS_Initialize_area( void *tls_area )
 {
-  uintptr_t                  alignment;
-  void                      *tls_data;
-  TLS_Thread_control_block  *tcb;
-  TLS_Dynamic_thread_vector *dtv;
-  void                      *return_value;
+  const volatile TLS_Configuration *config;
+  uintptr_t                         alignment;
+  void                             *tls_data;
+  TLS_Thread_control_block         *tcb;
+  TLS_Dynamic_thread_vector        *dtv;
+  void                             *return_value;
 #if CPU_THREAD_LOCAL_STORAGE_VARIANT == 11
-  uintptr_t                  tcb_size;
+  uintptr_t                         tcb_size;
 #endif
 #if CPU_THREAD_LOCAL_STORAGE_VARIANT == 20
-  uintptr_t                  size;
-  uintptr_t                  alignment_2;
+  uintptr_t                         size;
+  uintptr_t                         alignment_2;
 #endif
 
-  alignment = (uintptr_t) _TLS_Alignment;
+  config = &_TLS_Configuration;
+  alignment = (uintptr_t) config->alignment;
 
 #ifdef __i386__
   dtv = NULL;
@@ -249,7 +263,7 @@ static inline void *_TLS_Initialize_area( void *tls_area )
 #elif CPU_THREAD_LOCAL_STORAGE_VARIANT == 20
   alignment_2 = RTEMS_ALIGN_UP( alignment, CPU_SIZEOF_POINTER );
   tls_area = (void *) RTEMS_ALIGN_UP( (uintptr_t) tls_area, alignment_2 );
-  size = _TLS_Get_size();
+  size = (uintptr_t) config->size;
   tcb = (TLS_Thread_control_block *)
     ((char *) tls_area + RTEMS_ALIGN_UP( size, alignment_2 ));
   tls_data = (char *) tcb - RTEMS_ALIGN_UP( size, alignment );
@@ -259,7 +273,7 @@ static inline void *_TLS_Initialize_area( void *tls_area )
 #endif
 
   _TLS_Initialize_TCB_and_DTV( tls_data, tcb, dtv );
-  _TLS_Copy_and_clear( tls_data );
+  _TLS_Copy_and_clear( config, tls_data );
 
   return return_value;
 }
diff --git a/cpukit/score/src/tlsallocsize.c b/cpukit/score/src/tlsallocsize.c
index f78239192c..fa28391b83 100644
--- a/cpukit/score/src/tlsallocsize.c
+++ b/cpukit/score/src/tlsallocsize.c
@@ -10,7 +10,7 @@
  */
 
 /*
- * Copyright (C) 2014, 2022 embedded brains GmbH & Co. KG
+ * Copyright (C) 2014, 2023 embedded brains GmbH & Co. KG
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -42,14 +42,47 @@
 #include <rtems/score/interr.h>
 #include <rtems/score/thread.h>
 
+extern char _TLS_Data_begin[];
+
+extern char _TLS_Data_size[];
+
+extern char _TLS_BSS_begin[];
+
+extern char _TLS_BSS_size[];
+
+extern char _TLS_Size[];
+
+/**
+ * @brief The TLS section alignment.
+ *
+ * This symbol is provided by the linker command file as the maximum alignment
+ * of the .tdata and .tbss sections.  The linker ensures that the first TLS
+ * output section is aligned to the maximum alignment of all TLS output
+ * sections, see function _bfd_elf_tls_setup() in bfd/elflink.c of the GNU
+ * Binutils sources.  The linker command file must take into account the case
+ * that the .tdata section is empty and the .tbss section is non-empty.
+ */
+extern char _TLS_Alignment[];
+
+const volatile TLS_Configuration _TLS_Configuration = {
+  .data_begin = _TLS_Data_begin,
+  .data_size = _TLS_Data_size,
+  .bss_begin = _TLS_BSS_begin,
+  .bss_size = _TLS_BSS_size,
+  .size = _TLS_Size,
+  .alignment = _TLS_Alignment
+};
+
 static uintptr_t _TLS_Allocation_size;
 
 uintptr_t _TLS_Get_allocation_size( void )
 {
-  uintptr_t size;
-  uintptr_t allocation_size;
+  const volatile TLS_Configuration *config;
+  uintptr_t                         size;
+  uintptr_t                         allocation_size;
 
-  size = _TLS_Get_size();
+  config = &_TLS_Configuration;
+  size = (uintptr_t) config->size;
 
   if ( size == 0 ) {
     return 0;
@@ -66,7 +99,7 @@ uintptr_t _TLS_Get_allocation_size( void )
      * shall meet the stack alignment requirement.
      */
     stack_align = CPU_STACK_ALIGNMENT;
-    tls_align = RTEMS_ALIGN_UP( (uintptr_t) _TLS_Alignment, stack_align );
+    tls_align = RTEMS_ALIGN_UP( (uintptr_t) config->alignment, stack_align );
 
 #ifndef __i386__
     /* Reserve space for the dynamic thread vector */
diff --git a/testsuites/sptests/sptls01/init.c b/testsuites/sptests/sptls01/init.c
index acb5d43a5e..5dd49f4702 100644
--- a/testsuites/sptests/sptls01/init.c
+++ b/testsuites/sptests/sptls01/init.c
@@ -67,9 +67,11 @@ static void task(rtems_task_argument arg)
 
 static void check_tls_size(void)
 {
+  const volatile TLS_Configuration *config;
   uintptr_t tls_size;
 
-  tls_size = _TLS_Get_size();
+  config = &_TLS_Configuration;
+  tls_size = (uintptr_t) config->size;
 
   if (tls_size != 1) {
     printk(
-- 
2.35.3



More information about the devel mailing list