Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit b30cf11

Browse files
1c3t3ajakos-sec
andcommittedMar 17, 2025
Emit function declarations for functions with #[linkage="extern_weak"]
Currently, when declaring an extern weak function in Rust, we use the following syntax: ```rust unsafe extern "C" { #[linkage = "extern_weak"] static FOO: Option<unsafe extern "C" fn() -> ()>; } ``` This allows runtime-checking the extern weak symbol through the Option. When emitting LLVM-IR, the Rust compiler currently emits this static as an i8, and a pointer that is initialized with the value of the global i8 and represents the nullabilty e.g. ``` @foo = extern_weak global i8 @_rust_extern_with_linkage_FOO = internal global ptr @foo ``` This approach does not work well with CFI, where we need to attach CFI metadata to a concrete function declaration, which was pointed out in #115199. This change switches to emitting a proper function declaration instead of a global i8. This allows CFI to work for extern_weak functions. We keep initializing the Rust internal symbol with the function declaration, which preserves the correct behavior for runtime checking the Option. Co-authored-by: Jakob Koschel <jakobkoschel@google.com>
1 parent 705421b commit b30cf11

File tree

2 files changed

+48
-4
lines changed

2 files changed

+48
-4
lines changed
 

‎compiler/rustc_codegen_llvm/src/consts.rs

+24-4
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,17 @@ use rustc_abi::{
55
};
66
use rustc_codegen_ssa::common;
77
use rustc_codegen_ssa::traits::*;
8+
use rustc_hir::LangItem;
89
use rustc_hir::def::DefKind;
910
use rustc_hir::def_id::DefId;
1011
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
1112
use rustc_middle::mir::interpret::{
1213
Allocation, ConstAllocation, ErrorHandled, InitChunk, Pointer, Scalar as InterpScalar,
1314
read_target_uint,
1415
};
15-
use rustc_middle::mir::mono::MonoItem;
16-
use rustc_middle::ty::Instance;
16+
use rustc_middle::mir::mono::{Linkage, MonoItem};
1717
use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf};
18+
use rustc_middle::ty::{self, Instance};
1819
use rustc_middle::{bug, span_bug};
1920
use tracing::{debug, instrument, trace};
2021

@@ -171,8 +172,27 @@ fn check_and_apply_linkage<'ll, 'tcx>(
171172
if let Some(linkage) = attrs.import_linkage {
172173
debug!("get_static: sym={} linkage={:?}", sym, linkage);
173174

174-
// Declare a symbol `foo` with the desired linkage.
175-
let g1 = cx.declare_global(sym, cx.type_i8());
175+
// Declare a symbol `foo`. If `foo` is an extern_weak symbol, we declare
176+
// an extern_weak function, otherwise a global with the desired linkage.
177+
let g1 = if matches!(attrs.import_linkage, Some(Linkage::ExternalWeak)) {
178+
// An `extern_weak` function is represented as an `Option<unsafe extern ...>`,
179+
// we extract the function signature and declare it as an extern_weak function
180+
// instead of an extern_weak i8.
181+
let instance = Instance::mono(cx.tcx, def_id);
182+
if let ty::Adt(struct_def, args) = instance.ty(cx.tcx, cx.typing_env()).kind()
183+
&& cx.tcx.is_lang_item(struct_def.did(), LangItem::Option)
184+
&& let ty::FnPtr(sig, header) = args.type_at(0).kind()
185+
{
186+
let fn_sig = sig.with(*header);
187+
188+
let fn_abi = cx.fn_abi_of_fn_ptr(fn_sig, ty::List::empty());
189+
cx.declare_fn(sym, &fn_abi, None)
190+
} else {
191+
cx.declare_global(sym, cx.type_i8())
192+
}
193+
} else {
194+
cx.declare_global(sym, cx.type_i8())
195+
};
176196
llvm::set_linkage(g1, base::linkage_to_llvm(linkage));
177197

178198
// Declare an internal global `extern_with_linkage_foo` which
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Verifies that type metadata identifiers for for weakly-linked symbols are
2+
// emitted correctly.
3+
//
4+
//@ needs-sanitizer-cfi
5+
//@ compile-flags: -Clinker-plugin-lto -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
6+
#![crate_type = "bin"]
7+
#![feature(linkage)]
8+
9+
unsafe extern "C" {
10+
#[linkage = "extern_weak"]
11+
static FOO: Option<unsafe extern "C" fn(f64) -> ()>;
12+
}
13+
// CHECK: @_rust_extern_with_linkage_FOO = internal global ptr @FOO
14+
15+
fn main() {
16+
unsafe {
17+
if let Some(method) = FOO {
18+
method(4.2);
19+
// CHECK: call i1 @llvm.type.test(ptr {{%method|%0}}, metadata !"_ZTSFvdE")
20+
}
21+
}
22+
}
23+
24+
// CHECK: declare !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} extern_weak void @FOO(double) unnamed_addr #{{[0-9]+}}

0 commit comments

Comments
 (0)
Failed to load comments.