After much poking around, I finally figured out how to make this work!
The problem was that the ChibiOS initialization code had disabled
interrupts before the __early_init function was run, making the
bootloader not work despite my best intentions. This was fixed by
enabling interrupts just before jumping to the bootloader. This in turn
required changing to GNU-flavored C11 to include an inline assembly
instruction.