replace the system allocator in executables

This adds support for replacing the system allocator with jemalloc by
overriding the weak symbols on Linux (including Android). It is disabled
by default with #![no_std] and can be toggled via a compiler switch. It
will be possible to extend this to other platforms in the future.

This results in a performance improvement for memory allocation in C
along with reduced fragmentation. For example, the time spent on LLVM
passes in the Rust compiler on Linux is cut by 10% and peak memory usage
is reduced by 15%.

Closes #18896
I was under the impression that this "third party code" was primarily code in other processes that Rust itself was linked into. Either via a staticlib, dylib, or dlopen()'d dylib. Within a Rust executable itself (which this PR is focused on), however, I don't think that this would help too much. Libraries should be written knowing that the allocator is not their decision, and should plan appropriately (not relying on an upstream definition of jemalloc). Native code linked into an executable cannot rely on the existence of these symbols as the compiler is the one choosing whether to link in jemalloc or not, not the code itself.

Note that I'm just at this from the perspective of having this shim be as small as possible. I'd rather stick to well-known standardized apis like malloc than duplicate the nonstandard apis of jemalloc. If these were to fall out of sync with the jemalloc definitions, then I imagine badness could ensue.