From bc4aad37ca10e0f4a055f297ce4323c830c2afd5 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sat, 17 Jan 2026 13:30:47 +0100 Subject: [PATCH] naked-functions: properly document the -Zfunction-sections windows status --- .../rustc_codegen_ssa/src/mir/naked_asm.rs | 32 +++++++++++--- .../codegen-llvm/naked-fn/naked-functions.rs | 42 ++++++++++++------- 2 files changed, 54 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs index 4589ddbc3e2e..941267e4ecea 100644 --- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs +++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs @@ -8,7 +8,7 @@ use rustc_middle::{bug, ty}; use rustc_span::sym; use rustc_target::callconv::{ArgAbi, FnAbi, PassMode}; -use rustc_target::spec::{Arch, BinaryFormat}; +use rustc_target::spec::{Arch, BinaryFormat, Env}; use crate::common; use crate::mir::AsmCodegenMethods; @@ -234,6 +234,8 @@ fn prefix_and_suffix<'tcx>( writeln!(begin, ".pushsection {section},\"ax\", {progbits}").unwrap(); } else if function_sections { writeln!(begin, ".pushsection .text.{asm_name},\"ax\", {progbits}").unwrap(); + } else { + writeln!(begin, ".text").unwrap(); } writeln!(begin, ".balign {align_bytes}").unwrap(); write_linkage(&mut begin).unwrap(); @@ -261,7 +263,9 @@ fn prefix_and_suffix<'tcx>( } } BinaryFormat::MachO => { - // NOTE: LLVM ignores `-Zfunction-sections` on macos. + // NOTE: LLVM ignores `-Zfunction-sections` on macos. Instead the Mach-O symbol + // subsection splitting feature is used, which can be enabled with the + // `.subsections_via_symbols` global directive. LLVM already enables this directive. if let Some(section) = &link_section { writeln!(begin, ".pushsection {section},regular,pure_instructions").unwrap(); } @@ -289,9 +293,27 @@ fn prefix_and_suffix<'tcx>( writeln!(begin, ".endef").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, ".section {section},\"xr\"").unwrap() + } else if !function_sections { + // Function sections are enabled by default on MSVC, but disabled by default on GNU. + writeln!(begin, ".text").unwrap(); + } else { + // LLVM uses an extension to the section directive to support defining multiple + // sections with the same name and comdat. It adds `unique,` at the end of the + // `.section` directive. We have no way of generating that unique ID here, so don't + // emit it. + // + // See https://llvm.org/docs/Extensions.html#id2. + match &tcx.sess.target.options.env { + Env::Gnu => { + writeln!(begin, ".section .text${asm_name},\"xr\",one_only,{asm_name}") + .unwrap(); + } + Env::Msvc => { + writeln!(begin, ".section .text,\"xr\",one_only,{asm_name}").unwrap(); + } + other => bug!("invalid coff env {other:?}"), + } } write_linkage(&mut begin).unwrap(); writeln!(begin, ".balign {align_bytes}").unwrap(); diff --git a/tests/codegen-llvm/naked-fn/naked-functions.rs b/tests/codegen-llvm/naked-fn/naked-functions.rs index e83a62498bc5..a782ab5310e3 100644 --- a/tests/codegen-llvm/naked-fn/naked-functions.rs +++ b/tests/codegen-llvm/naked-fn/naked-functions.rs @@ -1,10 +1,17 @@ +// ignore-tidy-linelength +// //@ add-minicore -//@ revisions: linux win_x86_msvc win_x86_gnu win_i686_gnu macos thumb +//@ revisions: linux linux_no_function_sections macos thumb +//@ revisions: win_x86_msvc win_x86_gnu win_i686_gnu win_x86_gnu_function_sections // //@[linux] compile-flags: --target x86_64-unknown-linux-gnu //@[linux] needs-llvm-components: x86 +//@[linux_no_function_sections] compile-flags: --target x86_64-unknown-linux-gnu -Zfunction-sections=false +//@[linux_no_function_sections] needs-llvm-components: x86 //@[win_x86_gnu] compile-flags: --target x86_64-pc-windows-gnu //@[win_x86_gnu] needs-llvm-components: x86 +//@[win_x86_gnu_function_sections] compile-flags: --target x86_64-pc-windows-gnu -Zfunction-sections +//@[win_x86_gnu_function_sections] 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 @@ -21,20 +28,22 @@ extern crate minicore; use minicore::*; -// linux,win_x86,win_i686: .intel_syntax +// linux,win_x86_gnu,win_i686_gnu: .intel_syntax // // linux: .pushsection .text.naked_empty,\22ax\22, @progbits +// linux_no_function_sections: .text // macos-NOT: .pushsection // -// win_x86_msvc: .pushsection .text$naked_empty,\22xr\22 -// win_x86_gnu-NOT: .pushsection -// win_i686_gnu-NOT: .pushsection +// win_x86_msvc: .section .text,\22xr\22,one_only,naked_empty +// win_x86_gnu_function_sections: .section .text$naked_empty,\22xr\22,one_only,naked_empty +// win_x86_gnu-NOT: .section +// win_i686_gnu-NOT: .section // // thumb: .pushsection .text.naked_empty,\22ax\22, %progbits // // linux, macos, thumb: .balign 4 // -// linux,thumb: .globl naked_empty +// linux,win_x86_gnu,thumb: .globl naked_empty // macos: .globl _naked_empty // // CHECK-NOT: .private_extern @@ -63,7 +72,7 @@ // // CHECK-LABEL: naked_empty: // -// linux,macos,win_x86,win_x86: ret +// linux,macos,win_x86_msvc,win_x86_gnu,win_i686_gnu: ret // thumb: bx lr // // linux,windows,win_x86_msvc,thumb: .popsection @@ -86,20 +95,22 @@ pub extern "C" fn naked_empty() { } } -// linux,win_x86,win_i686: .intel_syntax +// linux,win_x86_gnu,win_i686_gnu,win_x86_msvc: .intel_syntax // // linux: .pushsection .text.naked_with_args_and_return,\22ax\22, @progbits +// linux_no_function_sections: .text // 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 +// win_x86_msvc: .section .text,\22xr\22,one_only,naked_with_args_and_return +// win_x86_gnu_function_sections: .section .text$naked_with_args_and_return,\22xr\22,one_only,naked_with_args_and_return +// win_x86_gnu-NOT: .section +// win_i686_gnu-NOT: .section // // thumb: .pushsection .text.naked_with_args_and_return,\22ax\22, %progbits // // linux, macos, thumb: .balign 4 // -// linux,thumb: .globl naked_with_args_and_return +// linux,win_x86_gnu,win_x86_msvc,win_i686_gnu,thumb: .globl naked_with_args_and_return // macos: .globl _naked_with_args_and_return // // CHECK-NOT: .private_extern @@ -132,7 +143,7 @@ pub extern "C" fn naked_empty() { // macos: add x0, x0, x1 // thumb: adds r0, r0, r1 // -// linux,macos,win_x86,win_i686: ret +// linux,macos,win_x86_msvc,win_x86_gnu,win_i686_gnu: ret // thumb: bx lr // // linux,windows,win_x86_msvc,thumb: .popsection @@ -158,9 +169,10 @@ pub extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize { } } -// linux: .pushsection .text.some_different_name,\22ax\22, @progbits +// linux,linux_no_function_sections: .pushsection .text.some_different_name,\22ax\22, @progbits // macos: .pushsection .text.some_different_name,regular,pure_instructions -// win_x86_msvc,win_x86_gnu,win_i686_gnu: .pushsection .text.some_different_name,\22xr\22 +// win_x86_msvc,win_x86_gnu,win_i686_gnu: .section .text.some_different_name,\22xr\22 +// win_x86_gnu_function_sections: .section .text.some_different_name,\22xr\22 // thumb: .pushsection .text.some_different_name,\22ax\22, %progbits // CHECK-LABEL: test_link_section: #[no_mangle]