OK, thanks. This all works now.
I actually did it a bit differently. This is the vector table in the "overlay". It is a copy of the standard table.
The _estack word should be redundant since SP is already set to top of RAM from the boot block, but putting 0 in there bombs it all, and I found it is required because the RTOS directly fetches that value for its internal use
The reset_handler is indeed redundant and I can't see it being used because a reset also clears VTOR, so the table in the boot block gets used instead, which is as intended.
If one did this scheme where the vector table, instead of main(), is at the
base of the overlay, one would have to enter the overlay by faking a hardware reset (but without changing VTOR - how?) to produce a jump to the 2nd vector and that would say
.word main
Or one would read out the 2nd vector value with code, and jmp to that, which doesn't actually get you anything.
I eliminated the code disappearance with
so there is a permanent (if unused) reference to main() which is non-removable because it is in an asm file.
The reason what I am doing seems weird is partly because I am not fully familiar with the arm32 environment (who is, at ~10k pages?) and partly because I am juggling multiple objectives which I have not posted here, partly for brevity and partly because I don't want to tell you all what I am developing
The reason why the various "keep" directives (in the C source and in the linkfile) seem to do nothing, remains unsolved. But I am not surprised; most websites that list compiler and linker directives are duff because there are so many versions. One can spend literally days on that.