From 2375a88a110a85cccb5e45bcb21077dc071e6314 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Fri, 17 Oct 2025 15:28:21 +0200 Subject: [PATCH 1/3] naked functions: respect `function_sections` on windows For `gnu` function_sections is off by default. --- .../rustc_codegen_ssa/src/mir/naked_asm.rs | 13 +++- .../codegen-llvm/naked-fn/naked-functions.rs | 66 ++++++++++--------- 2 files changed, 46 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs index e7239ebfecf63..c76026e03e247 100644 --- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs +++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs @@ -127,6 +127,8 @@ fn prefix_and_suffix<'tcx>( let is_arm = tcx.sess.target.arch == "arm"; let is_thumb = tcx.sess.unstable_target_features.contains(&sym::thumb_mode); + let function_sections = + tcx.sess.opts.unstable_opts.function_sections.unwrap_or(tcx.sess.target.function_sections); let attrs = tcx.codegen_instance_attrs(instance.def); let link_section = attrs.link_section.map(|symbol| symbol.as_str().to_string()); @@ -256,8 +258,11 @@ fn prefix_and_suffix<'tcx>( } } BinaryFormat::Coff => { - let section = link_section.unwrap_or_else(|| format!(".text.{asm_name}")); - writeln!(begin, ".pushsection {},\"xr\"", section).unwrap(); + if let Some(section) = &link_section { + writeln!(begin, ".pushsection {section},\"xr\"").unwrap() + } else if function_sections { + writeln!(begin, ".pushsection .text${asm_name},\"xr\"").unwrap() + } writeln!(begin, ".balign {align_bytes}").unwrap(); write_linkage(&mut begin).unwrap(); writeln!(begin, ".def {asm_name}").unwrap(); @@ -268,7 +273,9 @@ fn prefix_and_suffix<'tcx>( writeln!(end).unwrap(); writeln!(end, ".Lfunc_end_{asm_name}:").unwrap(); - writeln!(end, ".popsection").unwrap(); + if link_section.is_some() || function_sections { + writeln!(end, ".popsection").unwrap(); + } if !arch_suffix.is_empty() { writeln!(end, "{}", arch_suffix).unwrap(); } diff --git a/tests/codegen-llvm/naked-fn/naked-functions.rs b/tests/codegen-llvm/naked-fn/naked-functions.rs index 8a7ee4b4de563..8d659bdcaa847 100644 --- a/tests/codegen-llvm/naked-fn/naked-functions.rs +++ b/tests/codegen-llvm/naked-fn/naked-functions.rs @@ -1,12 +1,14 @@ //@ add-core-stubs -//@ revisions: linux win_x86 win_i686 macos thumb +//@ revisions: linux win_x86_msvc win_x86_gnu win_i686_gnu macos thumb // //@[linux] compile-flags: --target x86_64-unknown-linux-gnu //@[linux] needs-llvm-components: x86 -//@[win_x86] compile-flags: --target x86_64-pc-windows-gnu -//@[win_x86] needs-llvm-components: x86 -//@[win_i686] compile-flags: --target i686-pc-windows-gnu -//@[win_i686] needs-llvm-components: x86 +//@[win_x86_gnu] compile-flags: --target x86_64-pc-windows-gnu +//@[win_x86_gnu] needs-llvm-components: x86 +//@[win_x86_msvc] compile-flags: --target x86_64-pc-windows-msvc +//@[win_x86_msvc] needs-llvm-components: x86 +//@[win_i686_gnu] compile-flags: --target i686-pc-windows-gnu +//@[win_i686_gnu] needs-llvm-components: x86 //@[macos] compile-flags: --target aarch64-apple-darwin //@[macos] needs-llvm-components: aarch64 //@[thumb] compile-flags: --target thumbv7em-none-eabi @@ -23,8 +25,9 @@ use minicore::*; // // linux: .pushsection .text.naked_empty,\22ax\22, @progbits // macos: .pushsection __TEXT,__text,regular,pure_instructions -// win_x86: .pushsection .text.naked_empty,\22xr\22 -// win_i686: .pushsection .text._naked_empty,\22xr\22 +// win_x86_msvc: .pushsection .text$naked_empty,\22xr\22 +// win_x86_gnu-NOT: .pushsection +// win_i686_gnu-NOT: .pushsection // thumb: .pushsection .text.naked_empty,\22ax\22, %progbits // // CHECK: .balign 4 @@ -37,12 +40,12 @@ use minicore::*; // // linux: .type naked_empty, @function // -// win_x86: .def naked_empty -// win_i686: .def _naked_empty +// win_x86_msvc,win_x86_gnu: .def naked_empty +// win_i686_gnu: .def _naked_empty // -// win_x86,win_i686: .scl 2 -// win_x86,win_i686: .type 32 -// win_x86,win_i686: .endef +// win_x86_msvc,win_x86_gnu,win_i686_gnu: .scl 2 +// win_x86_msvc,win_x86_gnu,win_i686_gnu: .type 32 +// win_x86_msvc,win_x86_gnu,win_i686_gnu: .endef // // thumb: .type naked_empty, %function // thumb: .thumb @@ -53,7 +56,8 @@ use minicore::*; // linux,macos,win: ret // thumb: bx lr // -// CHECK: .popsection +// linux,windows,win_x86_msvc,thumb: .popsection +// win_x86_gnu-NOT,win_i686_gnu-NOT: .popsection // // thumb: .thumb // @@ -73,8 +77,9 @@ pub extern "C" fn naked_empty() { // // linux: .pushsection .text.naked_with_args_and_return,\22ax\22, @progbits // macos: .pushsection __TEXT,__text,regular,pure_instructions -// win_x86: .pushsection .text.naked_with_args_and_return,\22xr\22 -// win_i686: .pushsection .text._naked_with_args_and_return,\22xr\22 +// win_x86_msvc: .pushsection .text$naked_with_args_and_return,\22xr\22 +// win_x86_gnu-NOT: .pushsection +// win_i686_gnu-NOT: .pushsection // thumb: .pushsection .text.naked_with_args_and_return,\22ax\22, %progbits // // CHECK: .balign 4 @@ -87,12 +92,12 @@ pub extern "C" fn naked_empty() { // // linux: .type naked_with_args_and_return, @function // -// win_x86: .def naked_with_args_and_return -// win_i686: .def _naked_with_args_and_return +// win_x86_msvc,win_x86_gnu: .def naked_with_args_and_return +// win_i686_gnu: .def _naked_with_args_and_return // -// win_x86,win_i686: .scl 2 -// win_x86,win_i686: .type 32 -// win_x86,win_i686: .endef +// win_x86_msvc,win_x86_gnu,win_i686_gnu: .scl 2 +// win_x86_msvc,win_x86_gnu,win_i686_gnu: .type 32 +// win_x86_msvc,win_x86_gnu,win_i686_gnu: .endef // // thumb: .type naked_with_args_and_return, %function // thumb: .thumb @@ -100,14 +105,15 @@ pub extern "C" fn naked_empty() { // // CHECK-LABEL: naked_with_args_and_return: // -// linux, win_x86,win_i686: lea rax, [rdi + rsi] +// linux,win_x86_msvc,win_x86_gnu,win_i686_gnu: lea rax, [rdi + rsi] // macos: add x0, x0, x1 // thumb: adds r0, r0, r1 // // linux,macos,win: ret // thumb: bx lr // -// CHECK: .popsection +// linux,windows,win_x86_msvc,thumb: .popsection +// win_x86_gnu-NOT,win_i686_gnu-NOT: .popsection // // thumb: .thumb // @@ -134,7 +140,7 @@ pub extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize { // linux: .pushsection .text.some_different_name,\22ax\22, @progbits // macos: .pushsection .text.some_different_name,regular,pure_instructions -// win_x86,win_i686: .pushsection .text.some_different_name,\22xr\22 +// win_x86_msvc,win_x86_gnu,win_i686_gnu: .pushsection .text.some_different_name,\22xr\22 // thumb: .pushsection .text.some_different_name,\22ax\22, %progbits // CHECK-LABEL: test_link_section: #[no_mangle] @@ -148,15 +154,15 @@ pub extern "C" fn test_link_section() { naked_asm!("bx lr"); } -// win_x86: .def fastcall_cc -// win_i686: .def @fastcall_cc@4 +// win_x86_msvc,win_x86_gnu: .def fastcall_cc +// win_i686_gnu: .def @fastcall_cc@4 // -// win_x86,win_i686: .scl 2 -// win_x86,win_i686: .type 32 -// win_x86,win_i686: .endef +// win_x86_msvc,win_x86_gnu,win_i686_gnu: .scl 2 +// win_x86_msvc,win_x86_gnu,win_i686_gnu: .type 32 +// win_x86_msvc,win_x86_gnu,win_i686_gnu: .endef // -// win_x86-LABEL: fastcall_cc: -// win_i686-LABEL: @fastcall_cc@4: +// win_x86_msvc-LABEL,win_x86_gnu-LABEL: fastcall_cc: +// win_i686_gnu-LABEL: @fastcall_cc@4: #[cfg(target_os = "windows")] #[no_mangle] #[unsafe(naked)] From f3e38246ade057eaaad9a12599424f05d5c7c9f3 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Fri, 17 Oct 2025 15:54:41 +0200 Subject: [PATCH 2/3] naked functions: respect `function_sections` on linux/macos --- .../rustc_codegen_ssa/src/mir/naked_asm.rs | 22 +++++++++++++------ .../codegen-llvm/naked-fn/naked-functions.rs | 4 ++-- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs index c76026e03e247..a01ced20d0c90 100644 --- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs +++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs @@ -203,8 +203,6 @@ fn prefix_and_suffix<'tcx>( let mut end = String::new(); match asm_binary_format { BinaryFormat::Elf => { - let section = link_section.unwrap_or_else(|| format!(".text.{asm_name}")); - let progbits = match is_arm { true => "%progbits", false => "@progbits", @@ -215,7 +213,11 @@ fn prefix_and_suffix<'tcx>( false => "@function", }; - writeln!(begin, ".pushsection {section},\"ax\", {progbits}").unwrap(); + if let Some(section) = &link_section { + writeln!(begin, ".pushsection {section},\"ax\", {progbits}").unwrap(); + } else if function_sections { + writeln!(begin, ".pushsection .text.{asm_name},\"ax\", {progbits}").unwrap(); + } writeln!(begin, ".balign {align_bytes}").unwrap(); write_linkage(&mut begin).unwrap(); match item_data.visibility { @@ -234,14 +236,18 @@ fn prefix_and_suffix<'tcx>( // pattern match on assembly generated by LLVM. writeln!(end, ".Lfunc_end_{asm_name}:").unwrap(); writeln!(end, ".size {asm_name}, . - {asm_name}").unwrap(); - writeln!(end, ".popsection").unwrap(); + if link_section.is_some() || function_sections { + writeln!(end, ".popsection").unwrap(); + } if !arch_suffix.is_empty() { writeln!(end, "{}", arch_suffix).unwrap(); } } BinaryFormat::MachO => { - let section = link_section.unwrap_or_else(|| "__TEXT,__text".to_string()); - writeln!(begin, ".pushsection {},regular,pure_instructions", section).unwrap(); + // NOTE: LLVM ignores `-Zfunction-sections` on macos. + if let Some(section) = &link_section { + writeln!(begin, ".pushsection {section},regular,pure_instructions").unwrap(); + } writeln!(begin, ".balign {align_bytes}").unwrap(); write_linkage(&mut begin).unwrap(); match item_data.visibility { @@ -252,7 +258,9 @@ fn prefix_and_suffix<'tcx>( writeln!(end).unwrap(); writeln!(end, ".Lfunc_end_{asm_name}:").unwrap(); - writeln!(end, ".popsection").unwrap(); + if link_section.is_some() { + writeln!(end, ".popsection").unwrap(); + } if !arch_suffix.is_empty() { writeln!(end, "{}", arch_suffix).unwrap(); } diff --git a/tests/codegen-llvm/naked-fn/naked-functions.rs b/tests/codegen-llvm/naked-fn/naked-functions.rs index 8d659bdcaa847..6d0691bfbf969 100644 --- a/tests/codegen-llvm/naked-fn/naked-functions.rs +++ b/tests/codegen-llvm/naked-fn/naked-functions.rs @@ -24,7 +24,7 @@ use minicore::*; // linux,win: .intel_syntax // // linux: .pushsection .text.naked_empty,\22ax\22, @progbits -// macos: .pushsection __TEXT,__text,regular,pure_instructions +// macos-NOT: .pushsection // win_x86_msvc: .pushsection .text$naked_empty,\22xr\22 // win_x86_gnu-NOT: .pushsection // win_i686_gnu-NOT: .pushsection @@ -76,7 +76,7 @@ pub extern "C" fn naked_empty() { // linux,win: .intel_syntax // // linux: .pushsection .text.naked_with_args_and_return,\22ax\22, @progbits -// macos: .pushsection __TEXT,__text,regular,pure_instructions +// macos-NOT: .pushsection // win_x86_msvc: .pushsection .text$naked_with_args_and_return,\22xr\22 // win_x86_gnu-NOT: .pushsection // win_i686_gnu-NOT: .pushsection From 6580a5f7d75759c56d357089f454d3b5d2f2a065 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Fri, 17 Oct 2025 16:38:35 +0200 Subject: [PATCH 3/3] naked functions: add run-make test for DCE --- .../naked-dead-code-elimination/main.rs | 24 +++++++++++++++++++ .../naked-dead-code-elimination/rmake.rs | 10 ++++++++ 2 files changed, 34 insertions(+) create mode 100644 tests/run-make/naked-dead-code-elimination/main.rs create mode 100644 tests/run-make/naked-dead-code-elimination/rmake.rs diff --git a/tests/run-make/naked-dead-code-elimination/main.rs b/tests/run-make/naked-dead-code-elimination/main.rs new file mode 100644 index 0000000000000..8f64acd5f00fa --- /dev/null +++ b/tests/run-make/naked-dead-code-elimination/main.rs @@ -0,0 +1,24 @@ +use std::arch::naked_asm; + +#[unsafe(naked)] +#[no_mangle] +extern "C" fn used() { + naked_asm!("ret") +} + +#[unsafe(naked)] +#[no_mangle] +extern "C" fn unused() { + naked_asm!("ret") +} + +#[unsafe(naked)] +#[link_section = "foobar"] +#[no_mangle] +extern "C" fn unused_link_section() { + naked_asm!("ret") +} + +fn main() { + used(); +} diff --git a/tests/run-make/naked-dead-code-elimination/rmake.rs b/tests/run-make/naked-dead-code-elimination/rmake.rs new file mode 100644 index 0000000000000..1e1256f55b0fa --- /dev/null +++ b/tests/run-make/naked-dead-code-elimination/rmake.rs @@ -0,0 +1,10 @@ +//@ needs-asm-support + +use run_make_support::symbols::object_contains_any_symbol; +use run_make_support::{bin_name, rustc}; + +fn main() { + rustc().input("main.rs").opt().run(); + let mut unused = vec!["unused", "unused_link_section"]; + assert!(!object_contains_any_symbol(bin_name("main"), &unused)); +}