diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 8de68925cabbc..f0c47ac41e8a0 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -2015,6 +2015,12 @@ fn add_linked_symbol_object(
         file.set_mangling(object::write::Mangling::None);
     }
 
+    if file.format() == object::BinaryFormat::MachO {
+        // Divide up the sections into sub-sections via symbols for dead code stripping.
+        // Without this flag, unused `#[no_mangle]` or `#[used]` cannot be discard on MachO targets.
+        file.set_subsections_via_symbols();
+    }
+
     // ld64 requires a relocation to load undefined symbols, see below.
     // Not strictly needed if linking with lld, but might as well do it there too.
     let ld64_section_helper = if file.format() == object::BinaryFormat::MachO {
diff --git a/tests/ui/linking/cdylib-no-mangle.rs b/tests/ui/linking/cdylib-no-mangle.rs
new file mode 100644
index 0000000000000..f442c3f584d6e
--- /dev/null
+++ b/tests/ui/linking/cdylib-no-mangle.rs
@@ -0,0 +1,20 @@
+//@ only-apple
+//@ build-fail
+//@ dont-check-compiler-stderr
+//@ dont-check-compiler-stdout
+
+// Regression test for <https://github.com/rust-lang/rust/issues/139744>.
+// Functions in the dynamic library marked with no_mangle should not be GC-ed.
+
+#![crate_type = "cdylib"]
+
+unsafe extern "C" {
+    unsafe static THIS_SYMBOL_SHOULD_BE_UNDEFINED: usize;
+}
+
+#[unsafe(no_mangle)]
+pub unsafe fn function_marked_with_no_mangle() {
+    println!("FUNCTION_MARKED_WITH_NO_MANGLE = {}", unsafe { THIS_SYMBOL_SHOULD_BE_UNDEFINED });
+}
+
+//~? ERROR linking
diff --git a/tests/ui/linking/executable-no-mangle-strip.rs b/tests/ui/linking/executable-no-mangle-strip.rs
new file mode 100644
index 0000000000000..cc283dc53ee3a
--- /dev/null
+++ b/tests/ui/linking/executable-no-mangle-strip.rs
@@ -0,0 +1,27 @@
+//@ run-pass
+//@ ignore-windows-gnu: only statics marked with used can be GC-ed on windows-gnu
+
+// Regression test for <https://github.com/rust-lang/rust/issues/139744>.
+// Functions in the binary marked with no_mangle should be GC-ed if they
+// are not indirectly referenced by main.
+
+#![feature(used_with_arg)]
+
+#[cfg_attr(windows, link(name = "this_lib_does_not_exist", kind = "raw-dylib"))]
+unsafe extern "C" {
+    unsafe static THIS_SYMBOL_SHOULD_BE_UNDEFINED: usize;
+}
+
+#[unsafe(no_mangle)]
+pub unsafe fn function_marked_with_no_mangle() {
+    println!("FUNCTION_MARKED_WITH_NO_MANGLE = {}", unsafe { THIS_SYMBOL_SHOULD_BE_UNDEFINED });
+}
+
+#[used(compiler)]
+pub static FUNCTION_MARKED_WITH_USED: unsafe fn() = || {
+    println!("FUNCTION_MARKED_WITH_USED = {}", unsafe { THIS_SYMBOL_SHOULD_BE_UNDEFINED });
+};
+
+fn main() {
+    println!("MAIN");
+}