From 984fb02fd9bb2abdef0fbcad1899335e1efa081f Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 30 Mar 2026 18:03:19 +0200 Subject: [PATCH] test `#[naked]` with `#[link_section = "..."]` on windows --- .../rustc_codegen_ssa/src/mir/naked_asm.rs | 21 +++++--- .../naked-functions/link-section-windows.rs | 49 +++++++++++++++++++ tests/codegen-llvm/naked-fn/generics.rs | 12 ++--- .../codegen-llvm/naked-fn/naked-functions.rs | 34 ++++++++----- 4 files changed, 91 insertions(+), 25 deletions(-) create mode 100644 tests/assembly-llvm/naked-functions/link-section-windows.rs diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs index f12410c65d986..6ef232b09bc7a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs +++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs @@ -141,8 +141,14 @@ fn prefix_and_suffix<'tcx>( let attrs = tcx.codegen_instance_attrs(instance.def); let link_section = attrs.link_section.map(|symbol| symbol.as_str().to_string()); - // If no alignment is specified, an alignment of 4 bytes is used. - let align_bytes = attrs.alignment.map(|a| a.bytes()).unwrap_or(4); + // Pick a default alignment when the alignment is not explicitly specified. + let align_bytes = match attrs.alignment { + Some(align) => align.bytes(), + None => match asm_binary_format { + BinaryFormat::Coff => 16, + _ => 4, + }, + }; // In particular, `.arm` can also be written `.code 32` and `.thumb` as `.code 16`. let (arch_prefix, arch_suffix) = if is_arm { @@ -267,19 +273,18 @@ fn prefix_and_suffix<'tcx>( } } BinaryFormat::Coff => { - let section = link_section.unwrap_or_else(|| format!(".text.{asm_name}")); - writeln!(begin, ".pushsection {},\"xr\"", section).unwrap(); - writeln!(begin, ".balign {align_bytes}").unwrap(); - write_linkage(&mut begin).unwrap(); writeln!(begin, ".def {asm_name}").unwrap(); writeln!(begin, ".scl 2").unwrap(); writeln!(begin, ".type 32").unwrap(); writeln!(begin, ".endef").unwrap(); + + let section = link_section.unwrap_or_else(|| format!(".text.{asm_name}")); + writeln!(begin, ".pushsection {},\"xr\"", section).unwrap(); + write_linkage(&mut begin).unwrap(); + writeln!(begin, ".balign {align_bytes}").unwrap(); writeln!(begin, "{asm_name}:").unwrap(); writeln!(end).unwrap(); - writeln!(end, ".Lfunc_end_{asm_name}:").unwrap(); - writeln!(end, ".popsection").unwrap(); if !arch_suffix.is_empty() { writeln!(end, "{}", arch_suffix).unwrap(); } diff --git a/tests/assembly-llvm/naked-functions/link-section-windows.rs b/tests/assembly-llvm/naked-functions/link-section-windows.rs new file mode 100644 index 0000000000000..5823498973a33 --- /dev/null +++ b/tests/assembly-llvm/naked-functions/link-section-windows.rs @@ -0,0 +1,49 @@ +//@ revisions: windows-x86-gnu windows-x86-msvc +//@ add-minicore +//@ assembly-output: emit-asm +// +//@[windows-x86-gnu] compile-flags: --target x86_64-pc-windows-gnu +//@[windows-x86-gnu] needs-llvm-components: x86 +// +//@[windows-x86-msvc] compile-flags: --target x86_64-pc-windows-msvc +//@[windows-x86-msvc] needs-llvm-components: x86 + +#![crate_type = "lib"] +#![feature(no_core)] +#![no_core] + +// Tests that naked and non-naked functions emit the same directives when the function uses +// `#[link_section = "..."]`. + +extern crate minicore; +use minicore::*; + +#[unsafe(naked)] +#[unsafe(no_mangle)] +#[unsafe(link_section = "naked")] +extern "C" fn naked_ret() { + // CHECK: .def naked_ret; + // CHECK-NEXT: .scl 2; + // CHECK-NEXT: .type 32; + // CHECK-NEXT: .endef + // CHECK-NEXT: .section naked,"xr" + // CHECK-NEXT: .globl naked_ret + // CHECK-NEXT: .p2align 4 + // CHECK-NEXT: naked_ret: + // CHECK-NEXT: retq + naked_asm!("ret") +} + +#[unsafe(no_mangle)] +#[unsafe(link_section = "regular")] +extern "C" fn regular_ret() { + // CHECK: .def regular_ret; + // CHECK-NEXT: .scl 2; + // CHECK-NEXT: .type 32; + // CHECK-NEXT: .endef + // CHECK-NEXT: .section regular,"xr" + // CHECK-NEXT: .globl regular_ret + // CHECK-NEXT: .p2align 4 + // CHECK-NEXT: regular_ret: + // CHECK-NEXT: retq +} diff --git a/tests/codegen-llvm/naked-fn/generics.rs b/tests/codegen-llvm/naked-fn/generics.rs index b1e33ac348c6b..b85682699f45f 100644 --- a/tests/codegen-llvm/naked-fn/generics.rs +++ b/tests/codegen-llvm/naked-fn/generics.rs @@ -19,11 +19,11 @@ fn test(x: u64) { foo.trait_method(); } -// CHECK: .balign 4 +// CHECK: .balign // CHECK: add rax, 1 // CHECK: add rax, 42 -// CHECK: .balign 4 +// CHECK: .balign // CHECK: add rax, 2 // CHECK: add rax, 42 @@ -52,7 +52,7 @@ impl Invert for i64 { } } -// CHECK: .balign 4 +// CHECK: .balign // CHECK-LABEL: generic_function: // CHECK: call // CHECK: ret @@ -71,7 +71,7 @@ pub extern "C" fn generic_function(x: i64) -> i64 { #[repr(transparent)] struct Foo(u64); -// CHECK: .balign 4 +// CHECK: .balign // CHECK-LABEL: method: // CHECK: mov rax, rdi @@ -83,7 +83,7 @@ impl Foo { } } -// CHECK: .balign 4 +// CHECK: .balign // CHECK-LABEL: trait_method: // CHECK: mov rax, rdi @@ -99,7 +99,7 @@ impl Bar for Foo { } } -// CHECK: .balign 4 +// CHECK: .balign // CHECK-LABEL: naked_with_args_and_return: // CHECK: lea rax, [rdi + rsi] diff --git a/tests/codegen-llvm/naked-fn/naked-functions.rs b/tests/codegen-llvm/naked-fn/naked-functions.rs index 8cf643de7db01..f1ad07523f7f5 100644 --- a/tests/codegen-llvm/naked-fn/naked-functions.rs +++ b/tests/codegen-llvm/naked-fn/naked-functions.rs @@ -23,13 +23,11 @@ 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 // thumb: .pushsection .text.naked_empty,\22ax\22, %progbits // -// CHECK: .balign 4 +// linux, macos, thumb: .balign 4 // -// linux,win,thumb: .globl naked_empty +// linux,thumb: .globl naked_empty // macos: .globl _naked_empty // // CHECK-NOT: .private_extern @@ -44,16 +42,24 @@ use minicore::*; // win_x86,win_i686: .type 32 // win_x86,win_i686: .endef // +// win_x86: .pushsection .text.naked_empty,\22xr\22 +// win_i686: .pushsection .text._naked_empty,\22xr\22 +// +// win_x86: .globl naked_empty +// win_i686: .globl _naked_empty +// +// win_x86,win_i686: .balign 16 +// // thumb: .type naked_empty, %function // thumb: .thumb // thumb: .thumb_func // // CHECK-LABEL: naked_empty: // -// linux,macos,win: ret +// linux,macos,win_x86,win_x86: ret // thumb: bx lr // -// CHECK: .popsection +// linux,macos,thumb: .popsection // // thumb: .thumb // @@ -76,13 +82,11 @@ 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 // thumb: .pushsection .text.naked_with_args_and_return,\22ax\22, %progbits // -// CHECK: .balign 4 +// linux, macos, thumb: .balign 4 // -// linux,win,thumb: .globl naked_with_args_and_return +// linux,thumb: .globl naked_with_args_and_return // macos: .globl _naked_with_args_and_return // // CHECK-NOT: .private_extern @@ -97,6 +101,14 @@ pub extern "C" fn naked_empty() { // win_x86,win_i686: .type 32 // win_x86,win_i686: .endef // +// win_x86: .pushsection .text.naked_with_args_and_return,\22xr\22 +// win_i686: .pushsection .text._naked_with_args_and_return,\22xr\22 +// +// win_x86: .globl naked_with_args_and_return +// win_i686: .globl _naked_with_args_and_return +// +// win_x86,win_i686: .balign 16 +// // thumb: .type naked_with_args_and_return, %function // thumb: .thumb // thumb: .thumb_func @@ -110,7 +122,7 @@ pub extern "C" fn naked_empty() { // linux,macos,win: ret // thumb: bx lr // -// CHECK: .popsection +// linux,macos,thumb: .popsection // // thumb: .thumb //