Skip to content

Commit 6f935a0

Browse files
committed
Auto merge of #141061 - dpaoliello:shimasfn, r=bjorn3
Change __rust_no_alloc_shim_is_unstable to be a function This fixes a long sequence of issues: 1. A customer reported that building for Arm64EC was broken: #138541 2. This was caused by a bug in my original implementation of Arm64EC support, namely that only functions on Arm64EC need to be decorated with `#` but Rust was decorating statics as well. 3. Once I corrected Rust to only decorate functions, I started linking failures where the linker couldn't find statics exported by dylib dependencies. This was caused by the compiler not marking exported statics in the generated DEF file with `DATA`, thus they were being exported as functions not data. 4. Once I corrected the way that the DEF files were being emitted, the linker started failing saying that it couldn't find `__rust_no_alloc_shim_is_unstable`. This is because the MSVC linker requires the declarations of statics imported from other dylibs to be marked with `dllimport` (whereas it will happily link to functions imported from other dylibs whether they are marked `dllimport` or not). 5. I then made a change to ensure that `__rust_no_alloc_shim_is_unstable` was marked as `dllimport`, but the MSVC linker started emitting warnings that `__rust_no_alloc_shim_is_unstable` was marked as `dllimport` but was declared in an obj file. This is a harmless warning which is a performance hint: anything that's marked `dllimport` must be indirected via an `__imp` symbol so I added a linker arg in the target to suppress the warning. 6. A customer then reported a similar warning when using `lld-link` (<#140176 (comment)>). I don't think it was an implementation difference between the two linkers but rather that, depending on the obj that the declaration versus uses of `__rust_no_alloc_shim_is_unstable` landed in we would get different warnings, so I suppressed that warning as well: #140954. 7. Another customer reported that they weren't using the Rust compiler to invoke the linker, thus these warnings were breaking their build: <#140176 (comment)>. At that point, my original change was reverted (#141024) leaving Arm64EC broken yet again. Taking a step back, a lot of these linker issues arise from the fact that `__rust_no_alloc_shim_is_unstable` is marked as `extern "Rust"` in the standard library and, therefore, assumed to be a foreign item from a different crate BUT the Rust compiler may choose to generate it either in the current crate, some other crate that will be statically linked in OR some other crate that will by dynamically imported. Worse yet, it is impossible while building a given crate to know if `__rust_no_alloc_shim_is_unstable` will statically linked or dynamically imported: it might be that one of its dependent crates is the one with an allocator kind set and thus that crate (which is compiled later) will decide depending if it has any dylib dependencies or not to import `__rust_no_alloc_shim_is_unstable` or generate it. Thus, there is no way to know if the declaration of `__rust_no_alloc_shim_is_unstable` should be marked with `dllimport` or not. There is a simple fix for all this: there is no reason `__rust_no_alloc_shim_is_unstable` must be a static. It needs to be some symbol that must be linked in; thus, it could easily be a function instead. As a function, there is no need to mark it as `dllimport` when dynamically imported which avoids the entire mess above. There may be a perf hit for changing the `volatile load` to be a `tail call`, so I'm happy to change that part back (although I question what the codegen of a `volatile load` would look like, and if the backend is going to try to use load-acquire semantics). Build with this change applied BEFORE #140176 was reverted to demonstrate that there are no linking issues with either MSVC or MinGW: <https://github.com/rust-lang/rust/actions/runs/15078657205> Incidentally, I fixed `tests/run-make/no-alloc-shim` to work with MSVC as I needed it to be able to test locally (FYI for #128602) r? `@bjorn3` cc `@jieyouxu`
2 parents 1bb3352 + 6906b44 commit 6f935a0

File tree

18 files changed

+155
-131
lines changed

18 files changed

+155
-131
lines changed

compiler/rustc_ast/src/expand/allocator.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ pub fn alloc_error_handler_name(alloc_error_handler_kind: AllocatorKind) -> &'st
2222
}
2323
}
2424

25-
pub const NO_ALLOC_SHIM_IS_UNSTABLE: &str = "__rust_no_alloc_shim_is_unstable";
25+
pub const NO_ALLOC_SHIM_IS_UNSTABLE: &str = "__rust_no_alloc_shim_is_unstable_v2";
2626

2727
pub enum AllocatorTy {
2828
Layout,

compiler/rustc_codegen_cranelift/src/allocator.rs

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Allocator shim
22
// Adapted from rustc
33

4+
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
45
use rustc_ast::expand::allocator::{
56
ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE,
67
alloc_error_handler_name, default_fn_name, global_fn_name,
@@ -97,16 +98,31 @@ fn codegen_inner(
9798
data.define(Box::new([val]));
9899
module.define_data(data_id, &data).unwrap();
99100

100-
let data_id = module
101-
.declare_data(
102-
&mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE),
103-
Linkage::Export,
104-
false,
105-
false,
106-
)
107-
.unwrap();
108-
let mut data = DataDescription::new();
109-
data.set_align(1);
110-
data.define(Box::new([0]));
111-
module.define_data(data_id, &data).unwrap();
101+
{
102+
let sig = Signature {
103+
call_conv: module.target_config().default_call_conv,
104+
params: vec![],
105+
returns: vec![],
106+
};
107+
let func_id = module
108+
.declare_function(
109+
&mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE),
110+
Linkage::Export,
111+
&sig,
112+
)
113+
.unwrap();
114+
115+
let mut ctx = Context::new();
116+
ctx.func.signature = sig;
117+
let mut func_ctx = FunctionBuilderContext::new();
118+
let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx);
119+
120+
let block = bcx.create_block();
121+
bcx.switch_to_block(block);
122+
bcx.ins().return_(&[]);
123+
bcx.seal_all_blocks();
124+
bcx.finalize();
125+
126+
module.define_function(func_id, &mut ctx).unwrap();
127+
}
112128
}

compiler/rustc_codegen_gcc/src/allocator.rs

Lines changed: 42 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ pub(crate) unsafe fn codegen(
5757
let from_name = mangle_internal_symbol(tcx, &global_fn_name(method.name));
5858
let to_name = mangle_internal_symbol(tcx, &default_fn_name(method.name));
5959

60-
create_wrapper_function(tcx, context, &from_name, &to_name, &types, output);
60+
create_wrapper_function(tcx, context, &from_name, Some(&to_name), &types, output);
6161
}
6262
}
6363

@@ -66,7 +66,7 @@ pub(crate) unsafe fn codegen(
6666
tcx,
6767
context,
6868
&mangle_internal_symbol(tcx, "__rust_alloc_error_handler"),
69-
&mangle_internal_symbol(tcx, alloc_error_handler_name(alloc_error_handler_kind)),
69+
Some(&mangle_internal_symbol(tcx, alloc_error_handler_name(alloc_error_handler_kind))),
7070
&[usize, usize],
7171
None,
7272
);
@@ -81,21 +81,21 @@ pub(crate) unsafe fn codegen(
8181
let value = context.new_rvalue_from_int(i8, value as i32);
8282
global.global_set_initializer_rvalue(value);
8383

84-
let name = mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE);
85-
let global = context.new_global(None, GlobalKind::Exported, i8, name);
86-
#[cfg(feature = "master")]
87-
global.add_attribute(VarAttribute::Visibility(symbol_visibility_to_gcc(
88-
tcx.sess.default_visibility(),
89-
)));
90-
let value = context.new_rvalue_from_int(i8, 0);
91-
global.global_set_initializer_rvalue(value);
84+
create_wrapper_function(
85+
tcx,
86+
context,
87+
&mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE),
88+
None,
89+
&[],
90+
None,
91+
);
9292
}
9393

9494
fn create_wrapper_function(
9595
tcx: TyCtxt<'_>,
9696
context: &Context<'_>,
9797
from_name: &str,
98-
to_name: &str,
98+
to_name: Option<&str>,
9999
types: &[Type<'_>],
100100
output: Option<Type<'_>>,
101101
) {
@@ -124,34 +124,40 @@ fn create_wrapper_function(
124124
// TODO(antoyo): emit unwind tables.
125125
}
126126

127-
let args: Vec<_> = types
128-
.iter()
129-
.enumerate()
130-
.map(|(index, typ)| context.new_parameter(None, *typ, format!("param{}", index)))
131-
.collect();
132-
let callee = context.new_function(
133-
None,
134-
FunctionType::Extern,
135-
output.unwrap_or(void),
136-
&args,
137-
to_name,
138-
false,
139-
);
140-
#[cfg(feature = "master")]
141-
callee.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden));
142-
143127
let block = func.new_block("entry");
144128

145-
let args = args
146-
.iter()
147-
.enumerate()
148-
.map(|(i, _)| func.get_param(i as i32).to_rvalue())
149-
.collect::<Vec<_>>();
150-
let ret = context.new_call(None, callee, &args);
151-
//llvm::LLVMSetTailCall(ret, True);
152-
if output.is_some() {
153-
block.end_with_return(None, ret);
129+
if let Some(to_name) = to_name {
130+
let args: Vec<_> = types
131+
.iter()
132+
.enumerate()
133+
.map(|(index, typ)| context.new_parameter(None, *typ, format!("param{}", index)))
134+
.collect();
135+
let callee = context.new_function(
136+
None,
137+
FunctionType::Extern,
138+
output.unwrap_or(void),
139+
&args,
140+
to_name,
141+
false,
142+
);
143+
#[cfg(feature = "master")]
144+
callee.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden));
145+
146+
let args = args
147+
.iter()
148+
.enumerate()
149+
.map(|(i, _)| func.get_param(i as i32).to_rvalue())
150+
.collect::<Vec<_>>();
151+
let ret = context.new_call(None, callee, &args);
152+
//llvm::LLVMSetTailCall(ret, True);
153+
if output.is_some() {
154+
block.end_with_return(None, ret);
155+
} else {
156+
block.add_eval(None, ret);
157+
block.end_with_void_return(None);
158+
}
154159
} else {
160+
assert!(output.is_none());
155161
block.end_with_void_return(None);
156162
}
157163

compiler/rustc_codegen_llvm/src/allocator.rs

Lines changed: 42 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ pub(crate) unsafe fn codegen(
5757
let from_name = mangle_internal_symbol(tcx, &global_fn_name(method.name));
5858
let to_name = mangle_internal_symbol(tcx, &default_fn_name(method.name));
5959

60-
create_wrapper_function(tcx, &cx, &from_name, &to_name, &args, output, false);
60+
create_wrapper_function(tcx, &cx, &from_name, Some(&to_name), &args, output, false);
6161
}
6262
}
6363

@@ -66,7 +66,7 @@ pub(crate) unsafe fn codegen(
6666
tcx,
6767
&cx,
6868
&mangle_internal_symbol(tcx, "__rust_alloc_error_handler"),
69-
&mangle_internal_symbol(tcx, alloc_error_handler_name(alloc_error_handler_kind)),
69+
Some(&mangle_internal_symbol(tcx, alloc_error_handler_name(alloc_error_handler_kind))),
7070
&[usize, usize], // size, align
7171
None,
7272
true,
@@ -81,11 +81,16 @@ pub(crate) unsafe fn codegen(
8181
let llval = llvm::LLVMConstInt(i8, val as u64, False);
8282
llvm::set_initializer(ll_g, llval);
8383

84-
let name = mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE);
85-
let ll_g = cx.declare_global(&name, i8);
86-
llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility()));
87-
let llval = llvm::LLVMConstInt(i8, 0, False);
88-
llvm::set_initializer(ll_g, llval);
84+
// __rust_no_alloc_shim_is_unstable_v2
85+
create_wrapper_function(
86+
tcx,
87+
&cx,
88+
&mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE),
89+
None,
90+
&[],
91+
None,
92+
false,
93+
);
8994
}
9095

9196
if tcx.sess.opts.debuginfo != DebugInfo::None {
@@ -99,7 +104,7 @@ fn create_wrapper_function(
99104
tcx: TyCtxt<'_>,
100105
cx: &SimpleCx<'_>,
101106
from_name: &str,
102-
to_name: &str,
107+
to_name: Option<&str>,
103108
args: &[&Type],
104109
output: Option<&Type>,
105110
no_return: bool,
@@ -128,33 +133,38 @@ fn create_wrapper_function(
128133
attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]);
129134
}
130135

131-
let callee = declare_simple_fn(
132-
&cx,
133-
to_name,
134-
llvm::CallConv::CCallConv,
135-
llvm::UnnamedAddr::Global,
136-
llvm::Visibility::Hidden,
137-
ty,
138-
);
139-
if let Some(no_return) = no_return {
140-
// -> ! DIFlagNoReturn
141-
attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]);
142-
}
143-
llvm::set_visibility(callee, llvm::Visibility::Hidden);
144-
145136
let llbb = unsafe { llvm::LLVMAppendBasicBlockInContext(cx.llcx, llfn, c"entry".as_ptr()) };
146-
147137
let mut bx = SBuilder::build(&cx, llbb);
148-
let args = args
149-
.iter()
150-
.enumerate()
151-
.map(|(i, _)| llvm::get_param(llfn, i as c_uint))
152-
.collect::<Vec<_>>();
153-
let ret = bx.call(ty, callee, &args, None);
154-
llvm::LLVMSetTailCall(ret, True);
155-
if output.is_some() {
156-
bx.ret(ret);
138+
139+
if let Some(to_name) = to_name {
140+
let callee = declare_simple_fn(
141+
&cx,
142+
to_name,
143+
llvm::CallConv::CCallConv,
144+
llvm::UnnamedAddr::Global,
145+
llvm::Visibility::Hidden,
146+
ty,
147+
);
148+
if let Some(no_return) = no_return {
149+
// -> ! DIFlagNoReturn
150+
attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]);
151+
}
152+
llvm::set_visibility(callee, llvm::Visibility::Hidden);
153+
154+
let args = args
155+
.iter()
156+
.enumerate()
157+
.map(|(i, _)| llvm::get_param(llfn, i as c_uint))
158+
.collect::<Vec<_>>();
159+
let ret = bx.call(ty, callee, &args, None);
160+
llvm::LLVMSetTailCall(ret, True);
161+
if output.is_some() {
162+
bx.ret(ret);
163+
} else {
164+
bx.ret_void()
165+
}
157166
} else {
167+
assert!(output.is_none());
158168
bx.ret_void()
159169
}
160170
}

compiler/rustc_codegen_ssa/src/back/symbol_export.rs

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ fn exported_symbols_provider_local<'tcx>(
219219
.chain([
220220
mangle_internal_symbol(tcx, "__rust_alloc_error_handler"),
221221
mangle_internal_symbol(tcx, OomStrategy::SYMBOL),
222+
mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE),
222223
])
223224
{
224225
let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name));
@@ -232,19 +233,6 @@ fn exported_symbols_provider_local<'tcx>(
232233
},
233234
));
234235
}
235-
236-
let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(
237-
tcx,
238-
&mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE),
239-
));
240-
symbols.push((
241-
exported_symbol,
242-
SymbolExportInfo {
243-
level: SymbolExportLevel::Rust,
244-
kind: SymbolExportKind::Data,
245-
used: false,
246-
},
247-
))
248236
}
249237

250238
if tcx.sess.instrument_coverage() || tcx.sess.opts.cg.profile_generate.enabled() {

compiler/rustc_symbol_mangling/src/v0.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,6 @@ pub fn mangle_internal_symbol<'tcx>(tcx: TyCtxt<'tcx>, item_name: &str) -> Strin
8585
if item_name == "rust_eh_personality" {
8686
// rust_eh_personality must not be renamed as LLVM hard-codes the name
8787
return "rust_eh_personality".to_owned();
88-
} else if item_name == "__rust_no_alloc_shim_is_unstable" {
89-
// Temporary back compat hack to give people the chance to migrate to
90-
// include #[rustc_std_internal_symbol].
91-
return "__rust_no_alloc_shim_is_unstable".to_owned();
9288
}
9389

9490
let prefix = "_R";

library/alloc/src/alloc.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@ unsafe extern "Rust" {
3131
#[rustc_std_internal_symbol]
3232
fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8;
3333

34+
#[rustc_nounwind]
3435
#[rustc_std_internal_symbol]
35-
static __rust_no_alloc_shim_is_unstable: u8;
36+
fn __rust_no_alloc_shim_is_unstable_v2();
3637
}
3738

3839
/// The global memory allocator.
@@ -88,7 +89,7 @@ pub unsafe fn alloc(layout: Layout) -> *mut u8 {
8889
unsafe {
8990
// Make sure we don't accidentally allow omitting the allocator shim in
9091
// stable code until it is actually stabilized.
91-
core::ptr::read_volatile(&__rust_no_alloc_shim_is_unstable);
92+
__rust_no_alloc_shim_is_unstable_v2();
9293

9394
__rust_alloc(layout.size(), layout.align())
9495
}
@@ -171,7 +172,7 @@ pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 {
171172
unsafe {
172173
// Make sure we don't accidentally allow omitting the allocator shim in
173174
// stable code until it is actually stabilized.
174-
core::ptr::read_volatile(&__rust_no_alloc_shim_is_unstable);
175+
__rust_no_alloc_shim_is_unstable_v2();
175176

176177
__rust_alloc_zeroed(layout.size(), layout.align())
177178
}

src/tools/miri/src/shims/extern_static.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,6 @@ impl<'tcx> MiriMachine<'tcx> {
4545

4646
/// Sets up the "extern statics" for this machine.
4747
pub fn init_extern_statics(ecx: &mut MiriInterpCx<'tcx>) -> InterpResult<'tcx> {
48-
// "__rust_no_alloc_shim_is_unstable"
49-
let val = ImmTy::from_int(0, ecx.machine.layouts.u8); // always 0, value does not matter
50-
Self::alloc_extern_static(ecx, "__rust_no_alloc_shim_is_unstable", val)?;
51-
5248
// "__rust_alloc_error_handler_should_panic"
5349
let val = ecx.tcx.sess.opts.unstable_opts.oom.should_panic();
5450
let val = ImmTy::from_int(val, ecx.machine.layouts.u8);

src/tools/miri/src/shims/foreign_items.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,10 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
611611
this.write_pointer(new_ptr, dest)
612612
});
613613
}
614+
name if name == this.mangle_internal_symbol("__rust_no_alloc_shim_is_unstable_v2") => {
615+
// This is a no-op shim that only exists to prevent making the allocator shims instantly stable.
616+
let [] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
617+
}
614618

615619
// C memory handling functions
616620
"memcmp" => {

src/tools/miri/tests/pass/alloc-access-tracking.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#![no_std]
22
#![no_main]
3-
//@compile-flags: -Zmiri-track-alloc-id=20 -Zmiri-track-alloc-accesses -Cpanic=abort
4-
//@normalize-stderr-test: "id 20" -> "id $$ALLOC"
3+
//@compile-flags: -Zmiri-track-alloc-id=19 -Zmiri-track-alloc-accesses -Cpanic=abort
4+
//@normalize-stderr-test: "id 19" -> "id $$ALLOC"
55
//@only-target: linux # alloc IDs differ between OSes (due to extern static allocations)
66

77
extern "Rust" {

tests/codegen/alloc-optimisation.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
pub fn alloc_test(data: u32) {
66
// CHECK-LABEL: @alloc_test
77
// CHECK-NEXT: start:
8-
// CHECK-NEXT: {{.*}} load volatile i8, ptr @{{.*}}__rust_no_alloc_shim_is_unstable, align 1
8+
// CHECK-NEXT: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2
9+
// CHECK-NEXT: tail call void @_R{{.+}}__rust_no_alloc_shim_is_unstable_v2()
910
// CHECK-NEXT: ret void
1011
let x = Box::new(data);
1112
drop(x);

0 commit comments

Comments
 (0)