Skip to content

Each naked function creates separate PE code section #147789

@MauriceKayser

Description

@MauriceKayser

Description

(At least) on Windows, naked functions are not created in the .text section, but in a .text.First2LettersOfFunctionNameBecause8IsTheSectionNameLengthLimit section, e.g. .text.Ex for a naked function called Example.

Depending on the amount of naked functions, this can bloat the resulting binary file and memory usage.

Maybe the intention was to use the $ sign as a separator instead of a ., which is a magic separation character, as mentioned in #128177, for example .text$FunctionName instead of .text.FunctionName?

Example

  1. Create an example.rs:

    Rust code
    #![no_main]
    #![no_std]
    
    #[cfg(not(test))]
    #[panic_handler]
    fn panic(_: &core::panic::PanicInfo) -> ! {
        loop {}
    }
    
    // This ends up in the `.text.Wi` section
    #[unsafe(naked)]
    #[unsafe(no_mangle)]
    extern "system" fn WinMainCRTStartup() -> i32 {
        core::arch::naked_asm!("jmp {}", sym Hello)
    }
    
    // This ends up in the `.text.He` section
    #[unsafe(naked)]
    #[unsafe(no_mangle)]
    extern "system" fn Hello() -> i32 {
        core::arch::naked_asm!("jmp {}", sym Example)
    }
    
    // This ends up in the `.text.Ex` section
    #[unsafe(naked)]
    #[unsafe(no_mangle)]
    extern "system" fn Example() -> i32 {
        core::arch::naked_asm!("
            xor eax, eax
            ret
        ")
    }
  2. Compile via: rustc example.rs --emit asm,link,llvm-ir -C panic=abort -C "link-args=/Debug:None /EmitToolVersionInfo:No /NoCoffGrpInfo /NoVcFeature /SubSystem:Windows":

    dumpbin.exe /headers example.exe
    SECTION HEADER #1
    .text.Wi name
           5 virtual size
        1000 virtual address (0000000140001000 to 0000000140001004)
         200 size of raw data
         200 file pointer to raw data (00000200 to 000003FF)
    60000020 flags
             Code
             Execute Read
    
    SECTION HEADER #2
    .text.He name
           5 virtual size
        2000 virtual address (0000000140002000 to 0000000140002004)
         200 size of raw data
         400 file pointer to raw data (00000400 to 000005FF)
    60000020 flags
             Code
             Execute Read
    
    SECTION HEADER #3
    .text.Ex name
           3 virtual size
        3000 virtual address (0000000140003000 to 0000000140003002)
         200 size of raw data
         600 file pointer to raw data (00000600 to 000007FF)
    60000020 flags
             Code
             Execute Read
    LLVM module
    ; ModuleID = 'example.90d8d4ea2542351-cgu.0'
    source_filename = "example.90d8d4ea2542351-cgu.0"
    target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
    target triple = "x86_64-pc-windows-msvc"
    
    module asm ".intel_syntax"
    module asm ".pushsection .text.WinMainCRTStartup,\22xr\22"
    module asm ".balign 4"
    module asm ".globl WinMainCRTStartup"
    module asm ".def WinMainCRTStartup"
    module asm ".scl 2"
    module asm ".type 32"
    module asm ".endef"
    module asm "WinMainCRTStartup:"
    module asm "jmp Hello"
    module asm ".popsection"
    module asm ""
    module asm ".att_syntax"
    module asm ".intel_syntax"
    module asm ".pushsection .text.Hello,\22xr\22"
    module asm ".balign 4"
    module asm ".globl Hello"
    module asm ".def Hello"
    module asm ".scl 2"
    module asm ".type 32"
    module asm ".endef"
    module asm "Hello:"
    module asm "jmp Example"
    module asm ".popsection"
    module asm ""
    module asm ".att_syntax"
    module asm ".intel_syntax"
    module asm ".pushsection .text.Example,\22xr\22"
    module asm ".balign 4"
    module asm ".globl Example"
    module asm ".def Example"
    module asm ".scl 2"
    module asm ".type 32"
    module asm ".endef"
    module asm "Example:"
    module asm ""
    module asm "        xor eax, eax"
    module asm "        ret"
    module asm "    "
    module asm ".popsection"
    module asm ""
    module asm ".att_syntax"
    
    @llvm.compiler.used = appending global [2 x ptr] [ptr @Hello, ptr @Example], section "llvm.metadata"
    
    ; __rustc::rust_begin_unwind
    ; Function Attrs: noreturn nounwind uwtable
    define hidden void @_RNvCs691rhTbG0Ee_7___rustc17rust_begin_unwind(ptr align 8 %_1) unnamed_addr #0 {
    start:
      br label %bb1
    
    bb1:                                              ; preds = %bb1, %start
      br label %bb1
    }
    
    ; Function Attrs: noinline nounwind uwtable
    declare i32 @WinMainCRTStartup() unnamed_addr #1
    
    ; Function Attrs: noinline nounwind uwtable
    declare i32 @Hello() unnamed_addr #1
    
    ; Function Attrs: noinline nounwind uwtable
    declare i32 @Example() unnamed_addr #1
    
    attributes #0 = { noreturn nounwind uwtable "target-cpu"="x86-64" "target-features"="+cx16,+sse3,+sahf" }
    attributes #1 = { noinline nounwind uwtable "target-cpu"="x86-64" "target-features"="+cx16,+sse3,+sahf" }
    
    !llvm.module.flags = !{!0, !1}
    !llvm.ident = !{!2}
    
    !0 = !{i32 8, !"PIC Level", i32 2}
    !1 = !{i32 7, !"PIE Level", i32 2}
    !2 = !{!"rustc version 1.88.0 (6b00bc388 2025-06-23)"}
    Assembly module
        .def     @feat.00;
        .scl     3;
        .type    0;
        .endef
        .globl   @feat.00
    .set @feat.00, 0
        .file    "example.90d8d4ea2542351-cgu.0"
    
        .section .text.WinMainCRTStartup,"xr"
        .p2align 2
        .globl   WinMainCRTStartup
        .def     WinMainCRTStartup;
        .scl     2;
        .type    32;
        .endef
    WinMainCRTStartup:
        jmp      Hello
        .text
    
        .section .text.Hello,"xr"
        .p2align 2
        .globl   Hello
        .def     Hello;
        .scl     2;
        .type    32;
        .endef
    Hello:
        jmp      Example
        .text
    
        .section .text.Example,"xr"
        .p2align 2
        .globl   Example
        .def     Example;
        .scl     2;
        .type    32;
        .endef
    Example:
    
        xorl     %eax, %eax
        retq
    
        .text
    
        .def     _RNvCs691rhTbG0Ee_7___rustc17rust_begin_unwind;
        .scl     2;
        .type    32;
        .endef
        .section .text,"xr",one_only,_RNvCs691rhTbG0Ee_7___rustc17rust_begin_unwind
        .globl   _RNvCs691rhTbG0Ee_7___rustc17rust_begin_unwind
        .p2align 4
    _RNvCs691rhTbG0Ee_7___rustc17rust_begin_unwind:
        jmp      .LBB0_1
    .LBB0_1:
        jmp      .LBB0_1
  3. Explicitly set the section name with a $ separator to fix the issue:

    Rust code
    - // This ends up in the `.text.Wi` section
    + #[unsafe(link_section = ".text$WinMainCRTStartup")]
    
    - // This ends up in the `.text.He` section
    + #[unsafe(link_section = ".text$Hello")]
    
    - // This ends up in the `.text.Ex` section
    + #[unsafe(link_section = ".text$Example")]
  4. Compile again:

    dumpbin.exe /headers example.exe
    SECTION HEADER #1
       .text name
          11 virtual size
        1000 virtual address (0000000140001000 to 0000000140001010)
         200 size of raw data
         200 file pointer to raw data (00000200 to 000003FF)
    60000020 flags
             Code
             Execute Read
    LLVM module
    ; ModuleID = 'example.90d8d4ea2542351-cgu.0'
    source_filename = "example.90d8d4ea2542351-cgu.0"
    target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
    target triple = "x86_64-pc-windows-msvc"
    
    module asm ".intel_syntax"
    module asm ".pushsection .text$WinMainCRTStartup,\22xr\22"
    module asm ".balign 4"
    module asm ".globl WinMainCRTStartup"
    module asm ".def WinMainCRTStartup"
    module asm ".scl 2"
    module asm ".type 32"
    module asm ".endef"
    module asm "WinMainCRTStartup:"
    module asm "jmp Hello"
    module asm ".popsection"
    module asm ""
    module asm ".att_syntax"
    module asm ".intel_syntax"
    module asm ".pushsection .text$Hello,\22xr\22"
    module asm ".balign 4"
    module asm ".globl Hello"
    module asm ".def Hello"
    module asm ".scl 2"
    module asm ".type 32"
    module asm ".endef"
    module asm "Hello:"
    module asm "jmp Example"
    module asm ".popsection"
    module asm ""
    module asm ".att_syntax"
    module asm ".intel_syntax"
    module asm ".pushsection .text$Example,\22xr\22"
    module asm ".balign 4"
    module asm ".globl Example"
    module asm ".def Example"
    module asm ".scl 2"
    module asm ".type 32"
    module asm ".endef"
    module asm "Example:"
    module asm ""
    module asm "        xor eax, eax"
    module asm "        ret"
    module asm "    "
    module asm ".popsection"
    module asm ""
    module asm ".att_syntax"
    
    @llvm.compiler.used = appending global [2 x ptr] [ptr @Hello, ptr @Example], section "llvm.metadata"
    
    ; __rustc::rust_begin_unwind
    ; Function Attrs: noreturn nounwind uwtable
    define hidden void @_RNvCs691rhTbG0Ee_7___rustc17rust_begin_unwind(ptr align 8 %_1) unnamed_addr #0 {
    start:
      br label %bb1
    
    bb1:                                              ; preds = %bb1, %start
      br label %bb1
    }
    
    ; Function Attrs: noinline nounwind uwtable
    declare i32 @WinMainCRTStartup() unnamed_addr #1
    
    ; Function Attrs: noinline nounwind uwtable
    declare i32 @Hello() unnamed_addr #1
    
    ; Function Attrs: noinline nounwind uwtable
    declare i32 @Example() unnamed_addr #1
    
    attributes #0 = { noreturn nounwind uwtable "target-cpu"="x86-64" "target-features"="+cx16,+sse3,+sahf" }
    attributes #1 = { noinline nounwind uwtable "target-cpu"="x86-64" "target-features"="+cx16,+sse3,+sahf" }
    
    !llvm.module.flags = !{!0, !1}
    !llvm.ident = !{!2}
    
    !0 = !{i32 8, !"PIC Level", i32 2}
    !1 = !{i32 7, !"PIE Level", i32 2}
    !2 = !{!"rustc version 1.88.0 (6b00bc388 2025-06-23)"}
    Assembly module
        .def     @feat.00;
        .scl     3;
        .type    0;
        .endef
        .globl   @feat.00
    .set @feat.00, 0
        .file    "example.90d8d4ea2542351-cgu.0"
    
        .section .text$WinMainCRTStartup,"xr"
        .p2align 2
        .globl   WinMainCRTStartup
        .def     WinMainCRTStartup;
        .scl     2;
        .type    32;
        .endef
    WinMainCRTStartup:
        jmp      Hello
        .text
    
        .section .text$Hello,"xr"
        .p2align 2
        .globl   Hello
        .def     Hello;
        .scl     2;
        .type    32;
        .endef
    Hello:
        jmp      Example
        .text
    
        .section .text$Example,"xr"
        .p2align 2
        .globl   Example
        .def     Example;
        .scl     2;
        .type    32;
        .endef
    Example:
    
        xorl     %eax, %eax
        retq
    
        .text
    
        .def     _RNvCs691rhTbG0Ee_7___rustc17rust_begin_unwind;
        .scl     2;
        .type    32;
        .endef
        .section .text,"xr",one_only,_RNvCs691rhTbG0Ee_7___rustc17rust_begin_unwind
        .globl   _RNvCs691rhTbG0Ee_7___rustc17rust_begin_unwind
        .p2align 4
    _RNvCs691rhTbG0Ee_7___rustc17rust_begin_unwind:
        jmp      .LBB0_1
    .LBB0_1:
        jmp      .LBB0_1
  5. In comparison to naked functions, this does not happen with global_asm. Replace the 3 naked functions and their attributes with the following:

    Rust code
    // These end up in the `.text` section
    core::arch::global_asm!("
        .global WinMainCRTStartup
        WinMainCRTStartup:
            jmp Hello
    ");
    
    core::arch::global_asm!("
        .global Hello
        Hello:
            jmp Example
    ");
    
    core::arch::global_asm!("
        .global Example
        Example:
            xor eax, eax
            ret
    ");
  6. Compile again:

    dumpbin.exe /headers example.exe
    SECTION HEADER #1
    .text name
           7 virtual size
        1000 virtual address (0000000140001000 to 0000000140001006)
         200 size of raw data
         200 file pointer to raw data (00000200 to 000003FF)
    60000020 flags
             Code
             Execute Read
    LLVM module
    ; ModuleID = 'example.90d8d4ea2542351-cgu.0'
    source_filename = "example.90d8d4ea2542351-cgu.0"
    target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
    target triple = "x86_64-pc-windows-msvc"
    
    module asm ".intel_syntax"
    module asm ""
    module asm "    .global WinMainCRTStartup"
    module asm "    WinMainCRTStartup:"
    module asm "        jmp Hello"
    module asm ""
    module asm ".att_syntax"
    module asm ".intel_syntax"
    module asm ""
    module asm "    .global Hello"
    module asm "    Hello:"
    module asm "        jmp Example"
    module asm ""
    module asm ".att_syntax"
    module asm ".intel_syntax"
    module asm ""
    module asm "    .global Example"
    module asm "    Example:"
    module asm "        xor eax, eax"
    module asm "        ret"
    module asm ""
    module asm ".att_syntax"
    
    ; __rustc::rust_begin_unwind
    ; Function Attrs: noreturn nounwind uwtable
    define hidden void @_RNvCs691rhTbG0Ee_7___rustc17rust_begin_unwind(ptr align 8 %_1) unnamed_addr #0 {
    start:
    br label %bb1
    
    bb1:                                              ; preds = %bb1, %start
    br label %bb1
    }
    
    attributes #0 = { noreturn nounwind uwtable "target-cpu"="x86-64" "target-features"="+cx16,+sse3,+sahf" }
    
    !llvm.module.flags = !{!0, !1}
    !llvm.ident = !{!2}
    
    !0 = !{i32 8, !"PIC Level", i32 2}
    !1 = !{i32 7, !"PIE Level", i32 2}
    !2 = !{!"rustc version 1.88.0 (6b00bc388 2025-06-23)"}
    Assembly module
        .def     @feat.00;
        .scl     3;
        .type    0;
        .endef
        .globl   @feat.00
    .set @feat.00, 0
        .file    "example.90d8d4ea2542351-cgu.0"
    
        .globl   WinMainCRTStartup
    WinMainCRTStartup:
        jmp      Hello
    
        .globl   Hello
    Hello:
        jmp      Example
    
        .globl   Example
    Example:
        xorl     %eax, %eax
        retq
    
        .def     _RNvCs691rhTbG0Ee_7___rustc17rust_begin_unwind;
        .scl     2;
        .type    32;
        .endef
        .section .text,"xr",one_only,_RNvCs691rhTbG0Ee_7___rustc17rust_begin_unwind
        .globl   _RNvCs691rhTbG0Ee_7___rustc17rust_begin_unwind
        .p2align 4
    _RNvCs691rhTbG0Ee_7___rustc17rust_begin_unwind:
        jmp      .LBB0_1
    .LBB0_1:
        jmp      .LBB0_1

Expected result

The first example code should only create one section, named .text, instead of .text.Wi, .text.He, and .text.Ex.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-linkageArea: linking into static, shared libraries and binariesA-nakedArea: `#[naked]`, prologue and epilogue-free, functions, https://git.io/vAzzSC-bugCategory: This is a bug.O-windowsOperating system: WindowsT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions