diff --git a/arch/arm/src/common/arm_tls.c b/arch/arm/src/common/arm_tls.c index e01cb51ca7684..23812e7f881e3 100644 --- a/arch/arm/src/common/arm_tls.c +++ b/arch/arm/src/common/arm_tls.c @@ -30,6 +30,24 @@ #include "arm_internal.h" +/**************************************************************************** + * Private Function + ****************************************************************************/ + +/**************************************************************************** + * Name: arm_read_tp + * + * Description: + * Helper function for __aeabi_read_tp. + * This allows tls_get_info() macro to expand properly. + * + ****************************************************************************/ + +void *arm_read_tp(void) +{ + return (void *)(tls_get_info() + 1); +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -51,7 +69,7 @@ int up_tls_size(void) return sizeof(struct tls_info_s) + sizeof(void *) * 2 + - sizeof(uint32_t) * (_END_TBSS - _START_TDATA); + (_END_TBSS - _START_TDATA); } /**************************************************************************** @@ -67,15 +85,12 @@ int up_tls_size(void) void up_tls_initialize(struct tls_info_s *info) { - uint8_t *tls_data = (uint8_t *)(info + 1); - - uint32_t tdata_len = sizeof(uint32_t) * (_END_TDATA - _START_TDATA); - uint32_t tbss_len = sizeof(uint32_t) * (_END_TBSS - _START_TBSS); - - tls_data += sizeof(void *) * 2; + uint8_t *tls_data = (uint8_t *)(info + 1) + sizeof(void *) * 2; + uint32_t tdata_len = _END_TDATA - _START_TDATA; + uint32_t tbss_len = _END_TBSS - _START_TBSS; memcpy(tls_data, _START_TDATA, tdata_len); - memset(tls_data + tdata_len, 0, tbss_len); + memset(tls_data + tdata_len + (_START_TBSS - _END_TDATA), 0, tbss_len); } /**************************************************************************** @@ -84,9 +99,22 @@ void up_tls_initialize(struct tls_info_s *info) * Description: * Read thread local storage region pointer. * + * This function follows the ARM EABI specification for TLS helper + * functions: + * - Only r0 is modified (return value) + * - r1-r3 must be preserved for the caller + * + * The naked attribute ensures strict register usage compliance. + * ****************************************************************************/ +__attribute__((naked)) void *__aeabi_read_tp(void) { - return (void *)(tls_get_info() + 1); + __asm__ __volatile__ + ( + "push {r1-r3, lr}\n\t" + "bl arm_read_tp\n\t" + "pop {r1-r3, pc}\n\t" + ); }