Couldn't a non-libc "standard library" for a hypotethical language be written to be re-entrant safe so dealing with signals would be less painful? For example having a separate malloc-like heap for allocs inside signal handlers etc?
Signal handlers can interrupt other signal handlers. But you probably want to avoid this feature, lest you go mad, so let's ignore it.
Yes, you could write a library for use inside signal handlers that shares no state with the actual libc. Then you could also safely printf, for instance, although you'd jump ahead of any printfs in the host program that are still buffered, etc.
But it's not just libc's globals that are a problem, it's your own globals and those of any other libraries, and if you intend to do nontrivial work in the signal handler (such that having a compiler check that you're async-signal-safe is worth doing), you probably are actually trying to share state with the main program. For instance, say you're installing SEGV handler to virtually map a large data file into memory, fetching it from some remote file storage API as needed. You want access to some data structures from the main program to figure out what to map, probably the ability to make HTTPS connections, etc. And you have to do that all from the signal handler, because whatever pointer segfaulted has to be working by the time you return from your signal handler.
You might be able to do this with Rust plus cleverness, by putting the signal handler in a separate statically-linked crate and using the ownership system to track the fact that the signal handler needs read-only access to some data. (Or with dlmopen, in C.) But it would still be very complex.
mmap is sometimes used as an async signal safe allocation function. IIRC mmap async signal safety is not guaranteed by POSIX but it often is in practice on many platforms. It is not cheap though.
edit: I should have read ben0x539 comment which suggests the same thing.