One choice, for example, would be to rely on the bootloader's handling of .bss sections to allocate a temporary 'heap'. Haven't tried it, but it probably gets the job done well enough to bootstrap a real dynamic allocator. The point is, though, you can't just say "throw lazy-static and a custom allocator at the problem". Note, for example, my proposed solution requires writing the custom allocator entirely outside of Rust, since it can't access any Rust statics. It also requires two implementations of the custom allocator - one for bootstrapping, and the other after bootstrapping. These will have to be dynamically selected between at runtime since (AFAIK) Rust is hardly going to support static switching between them. Then you have to consider interoperability between them.
Finally, not all kernel designs are prepared to do any kind of dynamic allocation at all: microkernels which hand all available physical memory to userspace for management there cannot dynamically allocate (except, perhaps, for O(1) of allocation in a small, static heap - but at that point, what's the point?).