Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 25 additions & 10 deletions compiler/rustc_codegen_ssa/src/mir/naked_asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down Expand Up @@ -201,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",
Expand All @@ -213,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 {
Expand All @@ -232,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 {
Expand All @@ -250,14 +258,19 @@ 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();
}
}
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()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On -msvc targets, function_sections is ignored. .text$sym is only used on -gnu targets.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also LLVM currently generates the following line on COFF targets:

.section        {section},"xr",one_only,{sym},unique,0`

Should we be doing the same here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On -msvc targets, function_sections is ignored.

Meaning that it's just always assumed to be on? https://godbolt.org/z/a6ofW49YK

.text$sym is only used on -gnu targets.

It should still work for msvc, no?

Should we be doing the same here?

I don't think we can reliably emit the unique,id bit of that line because how do we make that ID?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually using -Zfunction-sections=no on msvc does have an effect. So I'm not really sure what it being ignored means then. Maybe this is a more recent LLVM change?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it's always assumed to be off on msvc. You can see it always uses .text.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does always use .text but normally it emits the line you quoted:

  .section .text,"xr",one_only,foo,unique,0

i.e. it uses a subsection which, as far as I understand, does allow DCE, with -Zfunction-sections=no it emits just

  .text

So then DCE is impossible

}
writeln!(begin, ".balign {align_bytes}").unwrap();
write_linkage(&mut begin).unwrap();
writeln!(begin, ".def {asm_name}").unwrap();
Expand All @@ -268,7 +281,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();
}
Expand Down
70 changes: 38 additions & 32 deletions tests/codegen-llvm/naked-fn/naked-functions.rs
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -22,9 +24,10 @@ use minicore::*;
// linux,win: .intel_syntax
//
// 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
// macos-NOT: .pushsection
// 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
Expand All @@ -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
Expand All @@ -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
//
Expand All @@ -72,9 +76,10 @@ 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
// win_x86: .pushsection .text.naked_with_args_and_return,\22xr\22
// win_i686: .pushsection .text._naked_with_args_and_return,\22xr\22
// 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
// thumb: .pushsection .text.naked_with_args_and_return,\22ax\22, %progbits
//
// CHECK: .balign 4
Expand All @@ -87,27 +92,28 @@ 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
// thumb: .thumb_func
//
// 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
//
Expand All @@ -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]
Expand All @@ -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)]
Expand Down
24 changes: 24 additions & 0 deletions tests/run-make/naked-dead-code-elimination/main.rs
Original file line number Diff line number Diff line change
@@ -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();
}
10 changes: 10 additions & 0 deletions tests/run-make/naked-dead-code-elimination/rmake.rs
Original file line number Diff line number Diff line change
@@ -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));
}
Loading