mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
freertos: fix TLS run-time address calculation
Since dd849ffc, _rodata_start label has been moved to a different linker output section from where the TLS templates (.tdata, .tbss) are located. Since link-time addresses of thread-local variables are calculated relative to the section start address, this resulted in incorrect calculation of THREADPTR/$tp registers. Fix by introducing new linker label, _flash_rodata_start, which points to the .flash.rodata output section where TLS variables are located, and use it when calculating THREADPTR/$tp. Also remove the hardcoded rodata section alignment for Xtensa targets. Alignment of rodata can be affected by the user application, which is the issue dd849ffc was fixing. To accommodate any possible alignment, save it in a linker label (_flash_rodata_align) and then use when calculating THREADPTR. Note that this is not required on RISC-V, since this target doesn't use TPOFF.
This commit is contained in:
parent
375f969d43
commit
b7707c54ce
@ -270,7 +270,6 @@ SECTIONS
|
||||
ASSERT(((_bss_end - ORIGIN(dram0_0_seg)) <= LENGTH(dram0_0_seg)),
|
||||
"DRAM segment data does not fit.")
|
||||
|
||||
/* When modifying the alignment, update tls_section_alignment in pxPortInitialiseStack */
|
||||
.flash.appdesc : ALIGN(0x10)
|
||||
{
|
||||
_rodata_start = ABSOLUTE(.);
|
||||
@ -286,6 +285,8 @@ SECTIONS
|
||||
|
||||
.flash.rodata : ALIGN(0x10)
|
||||
{
|
||||
_flash_rodata_start = ABSOLUTE(.);
|
||||
|
||||
mapping[flash_rodata]
|
||||
|
||||
|
||||
@ -343,6 +344,8 @@ SECTIONS
|
||||
. = ALIGN(4);
|
||||
} >default_rodata_seg
|
||||
|
||||
_flash_rodata_align = ALIGNOF(.flash.rodata);
|
||||
|
||||
.flash.text :
|
||||
{
|
||||
_stext = .;
|
||||
|
@ -300,7 +300,6 @@ SECTIONS
|
||||
_rodata_reserved_start = .;
|
||||
} > default_rodata_seg
|
||||
|
||||
/* When modifying the alignment, don't forget to update tls_section_alignment in pxPortInitialiseStack */
|
||||
.flash.appdesc : ALIGN(0x10)
|
||||
{
|
||||
_rodata_start = ABSOLUTE(.);
|
||||
@ -316,6 +315,8 @@ SECTIONS
|
||||
|
||||
.flash.rodata : ALIGN(0x10)
|
||||
{
|
||||
_flash_rodata_start = ABSOLUTE(.);
|
||||
|
||||
mapping[flash_rodata]
|
||||
|
||||
*(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */
|
||||
|
@ -265,7 +265,6 @@ SECTIONS
|
||||
_bss_end = ABSOLUTE(.);
|
||||
} > dram0_0_seg
|
||||
|
||||
/* When modifying the alignment, update tls_section_alignment in pxPortInitialiseStack */
|
||||
.flash.appdesc : ALIGN(0x10)
|
||||
{
|
||||
_rodata_reserved_start = ABSOLUTE(.);
|
||||
@ -282,6 +281,8 @@ SECTIONS
|
||||
|
||||
.flash.rodata : ALIGN(0x10)
|
||||
{
|
||||
_flash_rodata_start = ABSOLUTE(.);
|
||||
|
||||
mapping[flash_rodata]
|
||||
|
||||
*(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */
|
||||
@ -338,6 +339,8 @@ SECTIONS
|
||||
. = ALIGN(4);
|
||||
} >default_rodata_seg
|
||||
|
||||
_flash_rodata_align = ALIGNOF(.flash.rodata);
|
||||
|
||||
.flash.text :
|
||||
{
|
||||
_stext = .;
|
||||
|
@ -331,7 +331,6 @@ SECTIONS
|
||||
_rodata_reserved_start = .;
|
||||
} > default_rodata_seg
|
||||
|
||||
/* When modifying the alignment, don't forget to update tls_section_alignment in pxPortInitialiseStack */
|
||||
.flash.appdesc : ALIGN(0x10)
|
||||
{
|
||||
_rodata_start = ABSOLUTE(.);
|
||||
@ -347,6 +346,8 @@ SECTIONS
|
||||
|
||||
.flash.rodata : ALIGN(0x10)
|
||||
{
|
||||
_flash_rodata_start = ABSOLUTE(.);
|
||||
|
||||
mapping[flash_rodata]
|
||||
|
||||
*(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */
|
||||
@ -400,6 +401,8 @@ SECTIONS
|
||||
. = ALIGN(4);
|
||||
} > default_rodata_seg
|
||||
|
||||
_flash_rodata_align = ALIGNOF(.flash.rodata);
|
||||
|
||||
/* Marks the end of IRAM code segment */
|
||||
.iram0.text_end (NOLOAD) :
|
||||
{
|
||||
|
@ -225,18 +225,58 @@ StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxC
|
||||
extern uint32_t __global_pointer$;
|
||||
uint8_t* task_thread_local_start;
|
||||
uint8_t* threadptr;
|
||||
extern char _thread_local_start, _thread_local_end, _rodata_start;
|
||||
extern char _thread_local_start, _thread_local_end, _flash_rodata_start;
|
||||
|
||||
/* Byte pointer, so that subsequent calculations don't depend on sizeof(StackType_t). */
|
||||
uint8_t* sp = (uint8_t*) pxTopOfStack;
|
||||
|
||||
/* Set up TLS area */
|
||||
/* Set up TLS area.
|
||||
* The following diagram illustrates the layout of link-time and run-time
|
||||
* TLS sections.
|
||||
*
|
||||
* +-------------+
|
||||
* |Section: | Linker symbols:
|
||||
* |.flash.rodata| ---------------
|
||||
* 0x0+-------------+ <-- _flash_rodata_start
|
||||
* ^ | |
|
||||
* | | Other data |
|
||||
* | | ... |
|
||||
* | +-------------+ <-- _thread_local_start
|
||||
* | |.tbss | ^
|
||||
* v | | |
|
||||
* 0xNNNN|int example; | | (thread_local_size)
|
||||
* |.tdata | v
|
||||
* +-------------+ <-- _thread_local_end
|
||||
* | Other data |
|
||||
* | ... |
|
||||
* | |
|
||||
* +-------------+
|
||||
*
|
||||
* Local variables of
|
||||
* pxPortInitialiseStack
|
||||
* -----------------------
|
||||
* +-------------+ <-- pxTopOfStack
|
||||
* |.tdata (*) | ^
|
||||
* ^ |int example; | |(thread_local_size
|
||||
* | | | |
|
||||
* | |.tbss (*) | v
|
||||
* | +-------------+ <-- task_thread_local_start
|
||||
* 0xNNNN | | | ^
|
||||
* | | | |
|
||||
* | | | |_thread_local_start - _rodata_start
|
||||
* | | | |
|
||||
* | | | v
|
||||
* v +-------------+ <-- threadptr
|
||||
*
|
||||
* (*) The stack grows downward!
|
||||
*/
|
||||
|
||||
uint32_t thread_local_sz = (uint32_t) (&_thread_local_end - &_thread_local_start);
|
||||
thread_local_sz = ALIGNUP(0x10, thread_local_sz);
|
||||
sp -= thread_local_sz;
|
||||
task_thread_local_start = sp;
|
||||
memcpy(task_thread_local_start, &_thread_local_start, thread_local_sz);
|
||||
threadptr = task_thread_local_start - (&_thread_local_start - &_rodata_start);
|
||||
threadptr = task_thread_local_start - (&_thread_local_start - &_flash_rodata_start);
|
||||
|
||||
/* Simulate the stack frame as it would be created by a context switch interrupt. */
|
||||
sp -= RV_STK_FRMSZ;
|
||||
|
@ -189,7 +189,7 @@ StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t px
|
||||
#endif
|
||||
uint32_t *threadptr;
|
||||
void *task_thread_local_start;
|
||||
extern int _thread_local_start, _thread_local_end, _rodata_start;
|
||||
extern int _thread_local_start, _thread_local_end, _flash_rodata_start, _flash_rodata_align;
|
||||
// TODO: check that TLS area fits the stack
|
||||
uint32_t thread_local_sz = (uint8_t *)&_thread_local_end - (uint8_t *)&_thread_local_start;
|
||||
|
||||
@ -248,24 +248,25 @@ StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t px
|
||||
frame->vpri = 0xFFFFFFFF;
|
||||
#endif
|
||||
|
||||
/* Init threadptr reg and TLS vars */
|
||||
/* Init threadptr register and set up TLS run-time area.
|
||||
* The diagram in port/riscv/port.c illustrates the calculations below.
|
||||
*/
|
||||
task_thread_local_start = (void *)(((uint32_t)pxTopOfStack - XT_CP_SIZE - thread_local_sz) & ~0xf);
|
||||
memcpy(task_thread_local_start, &_thread_local_start, thread_local_sz);
|
||||
threadptr = (uint32_t *)(sp + XT_STK_EXTRA);
|
||||
/* Calculate THREADPTR value:
|
||||
/* Calculate THREADPTR value.
|
||||
* The generated code will add THREADPTR value to a constant value determined at link time,
|
||||
* to get the address of the TLS variable.
|
||||
* The constant value is calculated by the linker as follows
|
||||
* (search for 'tpoff' in elf32-xtensa.c in BFD):
|
||||
* offset = address - tls_section_vma + align_up(TCB_SIZE, tls_section_alignment)
|
||||
* where TCB_SIZE is hardcoded to 8. There doesn't seem to be a way to propagate
|
||||
* the section alignment value from the ld script into the code, so it is hardcoded
|
||||
* in both places.
|
||||
* where TCB_SIZE is hardcoded to 8.
|
||||
* Note this is slightly different compared to the RISC-V port, where offset = address - tls_section_vma.
|
||||
*/
|
||||
const uint32_t tls_section_alignment = 0x10; /* has to be in sync with ALIGN value of .flash.rodata section */
|
||||
const uint32_t tls_section_alignment = (uint32_t) &_flash_rodata_align; /* ALIGN value of .flash.rodata section */
|
||||
const uint32_t tcb_size = 8; /* Unrelated to FreeRTOS, this is the constant from BFD */
|
||||
const uint32_t base = (tcb_size + tls_section_alignment - 1) & (~(tls_section_alignment - 1));
|
||||
*threadptr = (uint32_t)task_thread_local_start - ((uint32_t)&_thread_local_start - (uint32_t)&_rodata_start) - base;
|
||||
*threadptr = (uint32_t)task_thread_local_start - ((uint32_t)&_thread_local_start - (uint32_t)&_flash_rodata_start) - base;
|
||||
|
||||
#if XCHAL_CP_NUM > 0
|
||||
/* Init the coprocessor save area (see xtensa_context.h) */
|
||||
|
Loading…
x
Reference in New Issue
Block a user