Compilation with security flags (2)

Some updates on the topic of hardening via CFLAGS.

The explorations reported on the 2022-12-22 entry of this phlog
turned out to be successful, in that I managed to enable stack
smashing protection (-fstack-protector and variants) under a
bare-metal build.  I updated the 2022-12-22 entry with my
findings about -fstack-protector.

The -D_FORTIFY_SOURCE setting was lately discovered to be enabled
by default in the toolchain configuration, which would explain
why I could not spot any difference between a build where it was
enabled, and a build where it was not.  It is still not clear if
the -D_FORTIFY_SOURCE accomplished anything on our build, given
that I couldn't appreciate any additional safety until
-fstack-protector was enabled.

My working implementation is currently using the "terminator
canary", which is a well known constant canary value.  A constant
canary is not as robust as a random canary, but it provides a
certain degree of protection (plenty of details can be found
online).  A constant canary has the advantage of being extremely
simple to implement.

Today a colleague suggested to use a randomised canary, so I've
spent some additional time in refining my implementation.

The newlib implementation can optionally use a randomised canary,
but it relies on features that are not available on our
bare-metal firmware.

We do have a (hardware) random number generator which we could
use for the purpose, but it needs to be initialised before we get
to use it.  Unfortunately, assigning the canary after the C
runtime has been set up breaks the stack smashing detection
mechanism.  Any return from a function is detected as a smashing.
This comes with no surprise: I had a clue when I noticed that
newlib assigns a random value to the canary within function
marked as '__attribute__((constructor))'

I don't believe that initialising the hardware from crt0 is a
good idea :D