Версия 3. Дышит в железе. Выяснилось, что проц спотыкается на
чтении слова без выравнивания, отсюда ".align 2". #include "ch32v00x.h"
#include <string.h>
static void __attribute__((used))
start2(void)
{
    extern char _data_lma[], _data_vma[], _edata[];
    memcpy(_data_vma, _data_lma, _edata - _data_vma);
    extern char _sbss[], _ebss[];
    memset(_sbss, 0, _ebss - _sbss);
    extern int main(void);
    main();
}
void __attribute__((naked, section(".init")))
_start(void)
{
    __asm volatile(
        "   j      3f                \n\t"
        "   .align 2                 \n\t"
        "1: .word  __global_pointer$ \n\t"   // literal pool of two constants
        "2: .word  _eusrstack        \n\t"   // keeps compiler from replacing them with registers
        "3: lw     gp, 1b            \n\t"   // load gp
        "   lw     sp, 2b            \n\t"   // load sp
        "   li     t0, 0x88          \n\t"   // enable
        "   csrw   mstatus, t0       \n\t"   //   interrupts
        "   csrwi  0x804, 2          \n\t"   // nesting on, HPE off
        "   csrwi  mtvec, 3          \n\t"   // table of vector addresses based at 0
        "   la     t0, start2        \n\t"   // exit
        "   csrw   mepc, t0          \n\t"   //    exception
        "   mret                     \n\t"); //       and proceed to start2
}
static void __attribute__((interrupt))
trap(void)
{
    int volatile w = 1;
    while (w) ;
}
//extern void SysTick_Handler(void);
static void (*const vectab[])(void) __attribute__((used, section(".init.vectors"))) = {
    [-1 + NonMaskableInt_IRQn] = trap,
    [-1 + HardFault_IRQn     ] = trap,
//    [-1 + SysTick_IRQn       ] = SysTick_Handler,
};