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 fb32abe

Browse files
1c3t3ajakos-sec
andcommittedMar 11, 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 b8b3830 commit fb32abe

File tree

2 files changed

+49
-5
lines changed

2 files changed

+49
-5
lines changed
 

‎compiler/rustc_codegen_llvm/src/consts.rs

+26-5
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,28 @@ 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, generic_args) = instance.ty(cx.tcx, cx.typing_env()).kind()
183+
&& cx.tcx.is_lang_item(struct_def.did(), LangItem::Option)
184+
&& let Some(first_arg) = generic_args.first()
185+
&& let ty::FnPtr(sig, header) = first_arg.expect_ty().kind()
186+
{
187+
let fn_sig = sig.with(*header);
188+
189+
let fn_abi = cx.fn_abi_of_fn_ptr(fn_sig, ty::List::empty());
190+
cx.declare_fn(sym, &fn_abi, None)
191+
} else {
192+
cx.declare_global(sym, cx.type_i8())
193+
}
194+
} else {
195+
cx.declare_global(sym, cx.type_i8())
196+
};
176197
llvm::set_linkage(g1, base::linkage_to_llvm(linkage));
177198

178199
// Declare an internal global `extern_with_linkage_foo` which
@@ -489,7 +510,7 @@ impl<'ll> CodegenCx<'ll, '_> {
489510
llvm::LLVMMDStringInContext2(self.llcx, bytes.as_c_char_ptr(), bytes.len());
490511
let data = [section, alloc];
491512
let meta = llvm::LLVMMDNodeInContext2(self.llcx, data.as_ptr(), data.len());
492-
let val = self.get_metadata_value(meta);
513+
let val = llvm::LLVMMetadataAsValue(self.llcx, meta);
493514
llvm::LLVMAddNamedMetadataOperand(
494515
self.llmod,
495516
c"wasm.custom_sections".as_ptr(),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Verifies that type metadata identifiers for trait objects are emitted correctly.
2+
//
3+
//@ needs-sanitizer-cfi
4+
//@ compile-flags: -Clinker-plugin-lto -Copt-level=0 -Zsanitizer=cfi
5+
#![crate_type = "bin"]
6+
#![feature(linkage)]
7+
8+
unsafe extern "C" {
9+
#[linkage = "extern_weak"]
10+
static FOO: Option<unsafe extern "C" fn(f64) -> ()>;
11+
}
12+
// CHECK: @_rust_extern_with_linkage_FOO = internal global ptr @FOO
13+
14+
fn main() {
15+
unsafe {
16+
if let Some(method) = FOO {
17+
method(4.2);
18+
// CHECK: call i1 @llvm.type.test(ptr {{%method|%0}}, metadata !"_ZTSFvdE")
19+
}
20+
}
21+
}
22+
23+
// 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.