Code change:
fs::write(&self.path, self.hash.as_deref().unwrap_or(b"")) } } <ins> #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct CrtBeginEnd { pub target: TargetSelection, } impl Step for CrtBeginEnd { type Output = PathBuf; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("src/llvm-project/compiler-rt/lib/crt") } fn make_run(run: RunConfig<'_>) { run.builder.ensure(CrtBeginEnd { target: run.target }); } /// Build crtbegin.o/crtend.o for musl target. fn run(self, builder: &Builder<'_>) -> Self::Output { let out_dir = builder.native_dir(self.target).join("crt"); if builder.config.dry_run { return out_dir; } let crtbegin_src = builder.src.join("src/llvm-project/compiler-rt/lib/crt/crtbegin.c"); let crtend_src = builder.src.join("src/llvm-project/compiler-rt/lib/crt/crtend.c"); if up_to_date(&crtbegin_src, &out_dir.join("crtbegin.o")) && up_to_date(&crtend_src, &out_dir.join("crtendS.o")) { return out_dir; } builder.info("Building crtbegin.o and crtend.o"); t!(fs::create_dir_all(&out_dir)); let mut cfg = cc::Build::new(); if let Some(ar) = builder.ar(self.target) { cfg.archiver(ar); } cfg.compiler(builder.cc(self.target)); cfg.cargo_metadata(false) .out_dir(&out_dir) .target(&self.target.triple) .host(&builder.config.build.triple) .warnings(false) .debug(false) .opt_level(3) .file(crtbegin_src) .file(crtend_src); // Those flags are defined in src/llvm-project/compiler-rt/lib/crt/CMakeLists.txt // Currently only consumer of those objects is musl, which use .init_array/.fini_array // instead of .ctors/.dtors cfg.flag("-std=c11") .define("CRT_HAS_INITFINI_ARRAY", None) .define("EH_USE_FRAME_REGISTRY", None); cfg.compile("crt"); t!(fs::copy(out_dir.join("crtbegin.o"), out_dir.join("crtbeginS.o"))); t!(fs::copy(out_dir.join("crtend.o"), out_dir.join("crtendS.o"))); out_dir } } </ins>

Related discussion:
text: At a high level the process looks like () Look for a "compact unwinding table" Look for "DWARF unwind information" Look for ARM EHABI unwind info Look for dynamically created DWARF unwind entries For Rust x8664 musl binaries, the compiler has provided DWARF unwind information, so we fall into the second bullet (): No compact encoding hint, so the first section isn't interesting Search the section for an index for the frame - not present Check the local cache in case we've seen this frame before - we haven't Scan the whole of the section for the address of interest - CRASH! Digging further, we see that the logic for scanning the sector looks like (): Read a length field If it's 0 stop, we're done - rustc never seems to generate this "end-of-information" marker Skip over CIE entries For non-CIE entries work out if the address we're looking for is in the range of the entry, if so we've got our FDE Jump forward by the length of the CFI entry In each loop we check that the newly found CIE entry is in a reasonable place (between and ). If it's not, bail out for safety and fail the lookup. Unfortunately, as in the linked issue originally is incorrectly set too big (it's set to which is almost always wrong) so the unwind code will step right off the end of the segment and into one of: (LSDA) - This starts with a signature that is approximately , which is bigger than the error introduced by the miscalculation, so (after failing to parse the LSDA as a CFI entry) it jumps forward out of the range and bails out because the of the "reasonable location" check I mentioned above. The gap before (if the did not have a length that's a multiple of 32 and thus there's padding between the sections). In this case when it tries to read the next entry one of three things happens: The padding bytes happen to have a large value (when interpreted as a ) and we're in a similar position to the case where there's no padding, fail to parse the CFI entry, try to jump to the next one, realise we're jumping out of the allowed range and bail out for safety.