> And structures, unions, pseudo-meta programming via the macro processors,
Those exists in macro assemblers, for they are extremely thin abstractions, no thicker than jumping to a label instead of jumping to an absolute or relative address.
> no exposure to IO unless on a CPU with MMIO.
Well, since not all processors have I/O instructions (or dedicated I/O pins), the easiest way to implement portability is simply to not provide a direct access to them in the language, and let library functions handle it.
> Those exists in macro assemblers, for they are extremely thin abstractions, no thicker than jumping to a label instead of jumping to an absolute or relative address.
They’re much more than that because of type aliasing, which is what lets you write -> . = operations all day without each one literally being a memory access in asm.
JOVIAL and Algol dialects were also designed for creating OSes and no one calls them low level.