> As far as the rest is concerned, not a single language in the world will provide you with primitives for that and make them portable across a thousand architectures with a million different peripherals.
I'm well aware, that's why I said.
> When you're dealing with the hardware architecture level you need more detail than C (or any PL) can reasonably provide.
A language does not need to provide every hardware primitive, just realize that it can't and implement a sane way to support hardware features that don't require abusing a cumbersome macro system and heavy compiler modification.
> That's the role of libraries and OSes with their drivers.
A ridiculous amount of vulnerabilities and wasted effort are sunk into operating systems and their drivers because of the garbage state of tooling for low level work. It's easy to make statements such as yours until it comes time to write/maintain a multi million line kernel and a only the lord knows how many line driver/subsystem fleet.
Kernel/driver devs do their best to make due, but the situation is far from ideal.
The information has to somehow be passed to the compiler, your options are: compiler specific features (see gcc attributes, etc), language level (see the fun that becomes with explicit_memset vs. memset) or a really fancy IR that can hold these types of requirements.
I'm confused in that, it's true, I've seen the macro system abused. But for working with things like memory mapped registers and interrupts you don't _need_ to abuse it. It actually looks really nice with with memory-mapped structures that ply on the register structure. Maybe I'm just missing something.
Special registers are just slots at specific memory addresses.
As far as the rest is concerned, not a single language in the world will provide you with primitives for that and make them portable across a thousand architectures with a million different peripherals. That's the role of libraries and OSes with their drivers.