Skip to content

Commit 58799ea

Browse files
committed
correctly emit .hidden
1 parent f38bc95 commit 58799ea

File tree

2 files changed

+61
-25
lines changed

2 files changed

+61
-25
lines changed

compiler/rustc_codegen_ssa/src/mir/naked_asm.rs

Lines changed: 54 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use crate::common;
22
use crate::mir::FunctionCx;
3-
use crate::traits::{AsmMethods, BuilderMethods, GlobalAsmOperandRef};
3+
use crate::traits::{AsmMethods, BuilderMethods, GlobalAsmOperandRef, MiscMethods};
4+
use rustc_attr::InstructionSetAttr;
45
use rustc_middle::bug;
6+
use rustc_middle::mir::mono::{Linkage, MonoItem, MonoItemData, Visibility};
57
use rustc_middle::mir::InlineAsmOperand;
68
use rustc_middle::ty;
79
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
@@ -29,7 +31,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
2931
let operands: Vec<_> =
3032
operands.iter().map(|op| self.inline_to_global_operand(op)).collect();
3133

32-
let (begin, end) = crate::mir::naked_asm::prefix_and_suffix(cx.tcx(), instance);
34+
let item_data = cx.codegen_unit().items().get(&MonoItem::Fn(instance)).unwrap();
35+
let (begin, end) = crate::mir::naked_asm::prefix_and_suffix(cx.tcx(), instance, item_data);
3336

3437
let mut template_vec = Vec::new();
3538
template_vec.push(rustc_ast::ast::InlineAsmTemplatePiece::String(begin));
@@ -90,7 +93,33 @@ impl AsmBinaryFormat {
9093
}
9194
}
9295

93-
fn prefix_and_suffix<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> (String, String) {
96+
fn linkage_directive(linkage: Linkage) -> Option<&'static str> {
97+
if true {
98+
// this is required. emitting nothing or .weak will emit
99+
//
100+
// > Global is external, but doesn't have external or weak linkage!
101+
//
102+
// and then aborts compilation
103+
return Some(".globl");
104+
}
105+
106+
match linkage {
107+
Linkage::External => Some(".globl"),
108+
Linkage::WeakAny | Linkage::WeakODR => Some(".weak"),
109+
Linkage::LinkOnceAny | Linkage::LinkOnceODR => Some(".weak"),
110+
Linkage::Internal | Linkage::Private => None, // just doesn't emit any attribute
111+
Linkage::ExternalWeak => None, // terminates with sigill on godbolt
112+
Linkage::AvailableExternally => None, // does not even emit the definition
113+
Linkage::Appending => None, // only valid on global variables
114+
Linkage::Common => None, // function may not have common linkage
115+
}
116+
}
117+
118+
fn prefix_and_suffix<'tcx>(
119+
tcx: TyCtxt<'tcx>,
120+
instance: Instance<'tcx>,
121+
item_data: &MonoItemData,
122+
) -> (String, String) {
94123
use std::fmt::Write;
95124

96125
let target = &tcx.sess.target;
@@ -109,19 +138,16 @@ fn prefix_and_suffix<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> (Stri
109138
.and_then(|attr| attr.value_str())
110139
.map(|attr| attr.as_str().to_string());
111140

112-
let instruction_set =
113-
tcx.get_attr(instance.def.def_id(), sym::instruction_set).and_then(|attr| attr.value_str());
114-
141+
let attrs = tcx.codegen_fn_attrs(instance.def_id());
115142
let (arch_prefix, arch_suffix) = if is_arm {
116143
(
117-
match instruction_set {
144+
match attrs.instruction_set {
118145
None => match is_thumb {
119146
true => ".thumb\n.thumb_func",
120147
false => ".arm",
121148
},
122-
Some(sym::a32) => ".arm",
123-
Some(sym::t32) => ".thumb\n.thumb_func",
124-
Some(other) => bug!("invalid instruction set: {other}"),
149+
Some(InstructionSetAttr::ArmA32) => ".arm",
150+
Some(InstructionSetAttr::ArmT32) => ".thumb\n.thumb_func",
125151
},
126152
match is_thumb {
127153
true => ".thumb",
@@ -150,10 +176,14 @@ fn prefix_and_suffix<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> (Stri
150176

151177
writeln!(begin, ".pushsection {section},\"ax\", {progbits}").unwrap();
152178
writeln!(begin, ".balign 4").unwrap();
153-
writeln!(begin, ".globl {asm_name}").unwrap();
154-
writeln!(begin, ".hidden {asm_name}").unwrap();
179+
if let Some(linkage) = linkage_directive(item_data.linkage) {
180+
writeln!(begin, "{linkage} {asm_name}").unwrap();
181+
}
182+
if let Visibility::Hidden = item_data.visibility {
183+
writeln!(begin, ".hidden {asm_name}").unwrap();
184+
}
155185
writeln!(begin, ".type {asm_name}, {function}").unwrap();
156-
if let Some(instruction_set) = instruction_set {
186+
if let Some(instruction_set) = attrs.instruction_set {
157187
writeln!(begin, "{}", instruction_set.as_str()).unwrap();
158188
}
159189
if !arch_prefix.is_empty() {
@@ -172,9 +202,13 @@ fn prefix_and_suffix<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> (Stri
172202
let section = opt_section.unwrap_or("__TEXT,__text".to_string());
173203
writeln!(begin, ".pushsection {},regular,pure_instructions", section).unwrap();
174204
writeln!(begin, ".balign 4").unwrap();
175-
writeln!(begin, ".globl {asm_name}").unwrap();
176-
writeln!(begin, ".private_extern {asm_name}").unwrap();
177-
if let Some(instruction_set) = instruction_set {
205+
if let Some(linkage) = linkage_directive(item_data.linkage) {
206+
writeln!(begin, "{linkage} {asm_name}").unwrap();
207+
}
208+
if let Visibility::Hidden = item_data.visibility {
209+
writeln!(begin, ".private_extern {asm_name}").unwrap();
210+
}
211+
if let Some(instruction_set) = attrs.instruction_set {
178212
writeln!(begin, "{}", instruction_set.as_str()).unwrap();
179213
}
180214
writeln!(begin, "{asm_name}:").unwrap();
@@ -189,12 +223,14 @@ fn prefix_and_suffix<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> (Stri
189223
let section = opt_section.unwrap_or(format!(".text.{asm_name}"));
190224
writeln!(begin, ".pushsection {},\"xr\"", section).unwrap();
191225
writeln!(begin, ".balign 4").unwrap();
192-
writeln!(begin, ".globl {asm_name}").unwrap();
226+
if let Some(linkage) = linkage_directive(item_data.linkage) {
227+
writeln!(begin, "{linkage} {asm_name}").unwrap();
228+
}
193229
writeln!(begin, ".def {asm_name}").unwrap();
194230
writeln!(begin, ".scl 2").unwrap();
195231
writeln!(begin, ".type 32").unwrap();
196232
writeln!(begin, ".endef {asm_name}").unwrap();
197-
if let Some(instruction_set) = instruction_set {
233+
if let Some(instruction_set) = attrs.instruction_set {
198234
writeln!(begin, "{}", instruction_set.as_str()).unwrap();
199235
}
200236
writeln!(begin, "{asm_name}:").unwrap();

tests/codegen/naked-fn/naked-functions.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55
#![crate_type = "lib"]
66
#![feature(naked_functions)]
77
use std::arch::{asm, global_asm};
8-
// CHECK: module asm ".intel_syntax"
9-
// CHECK: .pushsection .text.naked_empty,\22ax\22, @progbits
10-
// CHECK: .balign 4"
11-
// CHECK: .globl naked_empty"
12-
// CHECK: .hidden naked_empty"
13-
// CHECK: .type naked_empty, @function"
8+
// CHECK: module asm ".intel_syntax
9+
// CHECK: .pushsection .text.naked_empty,\22ax\22, @progbit
10+
// CHECK: .balign 4
11+
// CHECK: .globl naked_empty
12+
// CHECK-NOT: .hidden naked_empty
13+
// CHECK: .type naked_empty, @function
1414
// CHECK-LABEL: naked_empty:
1515
// CHECK: ret
1616
// CHECK: .popsection
@@ -26,7 +26,7 @@ pub unsafe extern "C" fn naked_empty() {
2626
// CHECK: .pushsection .text.naked_with_args_and_return,\22ax\22, @progbits
2727
// CHECK: .balign 4
2828
// CHECK: .globl naked_with_args_and_return
29-
// CHECK: .hidden naked_with_args_and_return
29+
// CHECK-NOT: .hidden naked_with_args_and_return
3030
// CHECK: .type naked_with_args_and_return, @function
3131
// CHECK-LABEL: naked_with_args_and_return:
3232
// CHECK: lea rax, [rdi + rsi]

0 commit comments

Comments
 (0)