forked from Imagelibrary/rtems
score: Fix TLS support for some code models
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.
This commit is contained in:
@@ -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
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
@@ -59,31 +59,51 @@ extern "C" {
|
|||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
extern char _TLS_Data_begin[];
|
/**
|
||||||
|
* @brief Represents the TLS configuration.
|
||||||
extern char _TLS_Data_end[];
|
*/
|
||||||
|
typedef struct {
|
||||||
extern char _TLS_Data_size[];
|
/**
|
||||||
|
* @brief This member is initialized to _TLS_Data_begin.
|
||||||
extern char _TLS_BSS_begin[];
|
*/
|
||||||
|
const char *data_begin;
|
||||||
extern char _TLS_BSS_end[];
|
|
||||||
|
|
||||||
extern char _TLS_BSS_size[];
|
|
||||||
|
|
||||||
extern char _TLS_Size[];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The TLS section alignment.
|
* @brief This member is initialized to _TLS_Data_size.
|
||||||
*
|
|
||||||
* 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 char *data_size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This member is initialized to _TLS_BSS_begin.
|
||||||
|
*/
|
||||||
|
const char *bss_begin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This member is initialized to _TLS_BSS_size.
|
||||||
|
*/
|
||||||
|
const char *bss_size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This member is initialized to _TLS_Size.
|
||||||
|
*/
|
||||||
|
const char *size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This member is initialized to _TLS_Alignment.
|
||||||
|
*/
|
||||||
|
const char *alignment;
|
||||||
|
} TLS_Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Provides the TLS configuration.
|
||||||
|
*
|
||||||
|
* 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 const volatile TLS_Configuration _TLS_Configuration;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/*
|
/*
|
||||||
@@ -115,39 +135,25 @@ typedef struct {
|
|||||||
uintptr_t offset;
|
uintptr_t offset;
|
||||||
} TLS_Index;
|
} 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.
|
* @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.
|
* @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
|
#if CPU_THREAD_LOCAL_STORAGE_VARIANT == 11
|
||||||
uintptr_t alignment;
|
uintptr_t alignment;
|
||||||
|
|
||||||
alignment = (uintptr_t) _TLS_Alignment;
|
alignment = (uintptr_t) config->alignment;
|
||||||
|
|
||||||
return RTEMS_ALIGN_UP( sizeof( TLS_Thread_control_block ), alignment );
|
return RTEMS_ALIGN_UP( sizeof( TLS_Thread_control_block ), alignment );
|
||||||
#else
|
#else
|
||||||
|
(void) config;
|
||||||
return sizeof( TLS_Thread_control_block );
|
return sizeof( TLS_Thread_control_block );
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -163,17 +169,23 @@ uintptr_t _TLS_Get_allocation_size( void );
|
|||||||
/**
|
/**
|
||||||
* @brief Initializes the thread-local storage data.
|
* @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.
|
* @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(
|
memset(
|
||||||
(char *) tls_data +
|
(char *) tls_data +
|
||||||
(uintptr_t) _TLS_BSS_begin - (uintptr_t) _TLS_Data_begin,
|
(uintptr_t) config->bss_begin - (uintptr_t) config->data_begin,
|
||||||
0,
|
0,
|
||||||
(uintptr_t) _TLS_BSS_size
|
(uintptr_t) config->bss_size
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,6 +225,7 @@ static inline void _TLS_Initialize_TCB_and_DTV(
|
|||||||
*/
|
*/
|
||||||
static inline void *_TLS_Initialize_area( void *tls_area )
|
static inline void *_TLS_Initialize_area( void *tls_area )
|
||||||
{
|
{
|
||||||
|
const volatile TLS_Configuration *config;
|
||||||
uintptr_t alignment;
|
uintptr_t alignment;
|
||||||
void *tls_data;
|
void *tls_data;
|
||||||
TLS_Thread_control_block *tcb;
|
TLS_Thread_control_block *tcb;
|
||||||
@@ -226,7 +239,8 @@ static inline void *_TLS_Initialize_area( void *tls_area )
|
|||||||
uintptr_t alignment_2;
|
uintptr_t alignment_2;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
alignment = (uintptr_t) _TLS_Alignment;
|
config = &_TLS_Configuration;
|
||||||
|
alignment = (uintptr_t) config->alignment;
|
||||||
|
|
||||||
#ifdef __i386__
|
#ifdef __i386__
|
||||||
dtv = NULL;
|
dtv = NULL;
|
||||||
@@ -249,7 +263,7 @@ static inline void *_TLS_Initialize_area( void *tls_area )
|
|||||||
#elif CPU_THREAD_LOCAL_STORAGE_VARIANT == 20
|
#elif CPU_THREAD_LOCAL_STORAGE_VARIANT == 20
|
||||||
alignment_2 = RTEMS_ALIGN_UP( alignment, CPU_SIZEOF_POINTER );
|
alignment_2 = RTEMS_ALIGN_UP( alignment, CPU_SIZEOF_POINTER );
|
||||||
tls_area = (void *) RTEMS_ALIGN_UP( (uintptr_t) tls_area, alignment_2 );
|
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 *)
|
tcb = (TLS_Thread_control_block *)
|
||||||
((char *) tls_area + RTEMS_ALIGN_UP( size, alignment_2 ));
|
((char *) tls_area + RTEMS_ALIGN_UP( size, alignment_2 ));
|
||||||
tls_data = (char *) tcb - RTEMS_ALIGN_UP( size, alignment );
|
tls_data = (char *) tcb - RTEMS_ALIGN_UP( size, alignment );
|
||||||
@@ -259,7 +273,7 @@ static inline void *_TLS_Initialize_area( void *tls_area )
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
_TLS_Initialize_TCB_and_DTV( tls_data, tcb, dtv );
|
_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;
|
return return_value;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ void *__tls_get_addr(const TLS_Index *ti)
|
|||||||
{
|
{
|
||||||
const Thread_Control *executing = _Thread_Get_executing();
|
const Thread_Control *executing = _Thread_Get_executing();
|
||||||
void *tls_data = (char *) executing->Registers.thread_id
|
void *tls_data = (char *) executing->Registers.thread_id
|
||||||
+ _TLS_Get_thread_control_block_area_size();
|
+ _TLS_Get_thread_control_block_area_size( &_TLS_Configuration );
|
||||||
|
|
||||||
assert(ti->module == 1);
|
assert(ti->module == 1);
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
@@ -42,14 +42,47 @@
|
|||||||
#include <rtems/score/interr.h>
|
#include <rtems/score/interr.h>
|
||||||
#include <rtems/score/thread.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;
|
static uintptr_t _TLS_Allocation_size;
|
||||||
|
|
||||||
uintptr_t _TLS_Get_allocation_size( void )
|
uintptr_t _TLS_Get_allocation_size( void )
|
||||||
{
|
{
|
||||||
|
const volatile TLS_Configuration *config;
|
||||||
uintptr_t size;
|
uintptr_t size;
|
||||||
uintptr_t allocation_size;
|
uintptr_t allocation_size;
|
||||||
|
|
||||||
size = _TLS_Get_size();
|
config = &_TLS_Configuration;
|
||||||
|
size = (uintptr_t) config->size;
|
||||||
|
|
||||||
if ( size == 0 ) {
|
if ( size == 0 ) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -66,7 +99,7 @@ uintptr_t _TLS_Get_allocation_size( void )
|
|||||||
* shall meet the stack alignment requirement.
|
* shall meet the stack alignment requirement.
|
||||||
*/
|
*/
|
||||||
stack_align = CPU_STACK_ALIGNMENT;
|
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__
|
#ifndef __i386__
|
||||||
/* Reserve space for the dynamic thread vector */
|
/* Reserve space for the dynamic thread vector */
|
||||||
|
|||||||
@@ -67,9 +67,11 @@ static void task(rtems_task_argument arg)
|
|||||||
|
|
||||||
static void check_tls_size(void)
|
static void check_tls_size(void)
|
||||||
{
|
{
|
||||||
|
const volatile TLS_Configuration *config;
|
||||||
uintptr_t tls_size;
|
uintptr_t tls_size;
|
||||||
|
|
||||||
tls_size = _TLS_Get_size();
|
config = &_TLS_Configuration;
|
||||||
|
tls_size = (uintptr_t) config->size;
|
||||||
|
|
||||||
if (tls_size != 1) {
|
if (tls_size != 1) {
|
||||||
printk(
|
printk(
|
||||||
|
|||||||
Reference in New Issue
Block a user