Code change:
return; } <ins> let self_contained_linker = sess.opts.cg.link_self_contained.linker(); // FIXME: some targets default to using `lld`, but users can only override the linker on the CLI // and cannot yet select the precise linker flavor to opt out of that. See for example issue // #113597 for the `thumbv6m-none-eabi` target: a driver is used, and its default linker // conflicts with the target's flavor, causing unexpected arguments being passed. // // Until the new `LinkerFlavor`-like CLI options are stabilized, we only adopt MCP510's behavior // if its dedicated unstable CLI flags are used, to keep the current sub-optimal stable // behavior. let using_mcp510 = self_contained_linker || sess.opts.cg.linker_flavor.is_some_and(|f| f.is_unstable()); if !using_mcp510 && !unstable_use_lld { return; } </ins> // 1. Implement the "self-contained" part of this feature by adding rustc distribution //    directories to the tool's search path. <del> let self_contained_linker = sess.opts.cg.link_self_contained.linker() || unstable_use_lld; if self_contained_linker { </del> <ins> if self_contained_linker || unstable_use_lld { </ins> for path in sess.get_tools_search_paths(false) { cmd.arg({ let mut arg = OsString::from("-B");

Related discussion:
text: The linker flavor used is a mix between what can be inferred from the CLI () and the target's default linker flavor: there is no linker flavor on the CLI (and that also offers another workaround on nightly: ), so it will have to be inferred to . in  infers a cc hint, and no hint about lld. the target's is combined in with these hints. We have our , but there is no hint about lld, . It's . so we now have our flavor is the linker people are expected to use on supposed to be some ? Is the default linker and flavor in correct ? In the meantime, I'll see to change this so that the lld flags are only when the unstable MCP510 options are used, to keep this stable and unfortunate behavior unchanged when the CLI and target conflict instead of compose.
Thanks for looking into this quickly! Most people building for will use the default linker today. It works fine for (I believe) all Rust-only projects. However, it's not uncommon to use , maybe to use specific GCC linker script directives, or just when hunting down linker-related bugs. For both of those use cases there's no problem with nightly, and I think the default in thumb_base is therefore fine. Some people do need to use when linking with pre-compiled C libraries - I understand that using gcc pulls in a target specific libc, and a lot of pre-compiled C libraries will be trying to link against symbols it exports which Rust doesn't. I believe does delegate to . Passing either or does work to get a build without errors, though I don't have a test case handy to check it's actually getting what people need out of . I'll try and dig around a bit more for the specific use cases where it's required over .
My main recollection is that gcc requires you to put in front of your linker arguments and using ld directly you don't But I think and friends are gcc options not ld options so maybe ld won't bring in libc and the C startup automatically. I'll test it out shortly.
main.c: Compile object code: Link with GCC: Link with ld: This does imply that for trivial invocations will include both the default start code (which provides ) and newlib (the C library), whilst will not.