Files
ThreadX4TGFS/port/moonlight/bootup.c
Eyck Jentzsch 1c9c00235d implements proper linker script to support TLS
This change updates the linker script and dependend wile so that thread local
storage sections are properly supported and initailaized
2026-02-01 21:49:17 +01:00

111 lines
3.5 KiB
C

/*
Simple C++ startup routine to setup CRT
SPDX-License-Identifier: Unlicense
(https://five-embeddev.com/ | http://www.shincbm.com/)
*/
#include <stdint.h>
#include <string.h>
#include <picotls.h>
#ifdef __cplusplus
#define EXTERN_C extern "C"
#else
#define EXTERN_C extern
#endif
// Generic C function pointer.
typedef void(*function_t)(void) ;
// These symbols are defined by the linker script.
// See linker.lds
EXTERN_C uint8_t __bss_start;
EXTERN_C uint8_t __bss_end;
EXTERN_C const uint8_t __data_source;
EXTERN_C uint8_t __data_start;
EXTERN_C uint8_t __data_end;
EXTERN_C const uint8_t __data_source;
EXTERN_C uint8_t __tbss_start;
EXTERN_C uintptr_t __tbss_size;
EXTERN_C const uint8_t __tdata_source;
EXTERN_C uint8_t __tls_base;
EXTERN_C uintptr_t __tdata_size;
EXTERN_C function_t __init_array_start;
EXTERN_C function_t __init_array_end;
EXTERN_C function_t __fini_array_start;
EXTERN_C function_t __fini_array_end;
// This function will be placed by the linker script according to the section
// Raw function 'called' by the CPU with no runtime.
EXTERN_C void _start(void) __attribute__ ((naked,section(".text.boot")));
// Entry and exit points as C functions.
EXTERN_C void _initialize(void) __attribute__ ((noreturn,section(".text.boot")));
EXTERN_C void _exit(int exit_code) __attribute__ ((noreturn,noinline,weak));
// Standard entry point, no arguments.
extern int main(void);
// The linker script will place this in the reset entry point.
// It will be 'called' with no stack or C runtime configuration.
// NOTE - this only supports a single hart.
// tp will not be initialized
void _start(void) {
// Setup SP and GP
// The locations are defined in the linker script
__asm__ volatile (
".option push;"
// The 'norelax' option is critical here.
// Without 'norelax' the global pointer will
// be loaded relative to the global pointer!
".option norelax;"
"la gp, __global_pointer$;"
".option pop;"
"la sp, _sp;"
"jal zero, _initialize;"
: /* output: none %0 */
: /* input: none */
: /* clobbers: none */);
// This point will not be executed, _initialize() will be called with no return.
}
// At this point we have a stack and global poiner, but no access to global variables.
void _initialize(void) {
// Init memory regions
// Clear the .bss section (global variables with no initial values)
memset((void*) &__bss_start, 0, (&__bss_end - &__bss_start));
// Initialize the .data section (global variables with initial values)
memcpy((void*)&__data_start, (const void*)&__data_source, (&__data_end - &__data_start));
// Clear the .tbss section (thread local variables with no initial values)
memset((void*) &__tbss_start, 0, __tbss_size);
// Initialize the .tls section (thread local variables with initial values)
memcpy((void*) &__tls_base, (const void*)&__tdata_source, __tdata_size);
// Call constructors
for (const function_t* entry=&__init_array_start;
entry < &__init_array_end;
++entry) {
(*entry)();
}
#ifdef __THREAD_LOCAL_STORAGE
_set_tls(__tls_base)
#endif
int rc = main();
// Call destructors
for (const function_t* entry=&__fini_array_start;
entry < &__fini_array_end;
++entry) {
(*entry)();
}
_exit(rc);
}
// This should never be called. Busy loop with the CPU in idle state.
void _exit(int exit_code) {
(void)exit_code;
// Halt
while (1) {
__asm__ volatile ("wfi");
}
}