Yes - this worked also. The "extern" is the key hack
extern int main();
main();
This is just a way to show that you are a C expert

extern uint32_t code_base;
goto *(&code_base);
I really have no idea what line 2 does. & takes the address of, but why the * ? I've never used function pointers in C. Only in asm. Anyway, can't beat asm; it does exactly what it says on the tin

it would be good to place memory barriers, invalidate cache (if present), and set up the stack pointer.
I do this just before the jmp:
// Set SP to top of RAM
asm volatile ("ldr sp, = _estack \n");
Then I guess add some code from the cmsis headers before the goto- __set_MSP, __DMB, etc.
Why, when this is just one load of code transferring control to another load of code? And it happens before interrupts are enabled, before RTOS starts...
Somebody said above that library (.a) is only a collection of .o. It is, but the linker does not treat it as such. There are several subtle but important differences, one being that weak symbols from .o are not overriden by symbols from .a.
That's staggering.
But I don't think it is my problem right now. I have weak symbols in a .s file and am trying to override them with a .c (compiled to .o) file. I continue to work on this one. It works in another version of the project and has done so for years, so is somehow very narrowly context dependent.
Still amazed over those KEEP directives. Mostly they are unnecessary BS which people just throw everywhere.
Same with the __libc_init_array stuff apparently. Somebody put it there and everybody just left it. All I see is this in the .map file
.preinit_array 0x000000000807095c 0x0
0x000000000807095c PROVIDE (__preinit_array_start = .)
*(.preinit_array*)
0x000000000807095c PROVIDE (__preinit_array_end = .)
.init_array 0x000000000807095c 0x8
0x000000000807095c PROVIDE (__init_array_start = .)
*(SORT_BY_NAME(.init_array.*))
.init_array.00000
0x000000000807095c 0x4 ../LIBC/LIBCW\libc-weakened.a(lib_a-__call_atexit.o)
*(.init_array*)
.init_array 0x0000000008070960 0x4 c:/st/stm32cubeide_1.11.0/stm32cubeide/plugins/com.st.stm32cube.ide.mcu.externaltools.gnu-tools-for-stm32.10.3-2021.10.win32_1.0.200.202301161003/tools/bin/../lib/gcc/arm-none-eabi/10.3.1/thumb/v7e-m+fp/hard/crtbegin.o
0x0000000008070964 PROVIDE (__init_array_end = .)
.fini_array 0x0000000008070964 0x4
0x0000000008070964 PROVIDE (__fini_array_start = .)
*(.fini_array*)
.fini_array 0x0000000008070964 0x4 c:/st/stm32cubeide_1.11.0/stm32cubeide/plugins/com.st.stm32cube.ide.mcu.externaltools.gnu-tools-for-stm32.10.3-2021.10.win32_1.0.200.202301161003/tools/bin/../lib/gcc/arm-none-eabi/10.3.1/thumb/v7e-m+fp/hard/crtbegin.o
*(SORT_BY_NAME(.fini_array.*))
0x0000000008070968 PROVIDE (__fini_array_end = .)