about summary refs log tree commit diff
path: root/compiler/rustc_codegen_llvm/src/consts.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_codegen_llvm/src/consts.rs')
-rw-r--r--compiler/rustc_codegen_llvm/src/consts.rs237
1 files changed, 231 insertions, 6 deletions
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index 0b96b63bc85..a110ecbb75d 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -4,17 +4,19 @@ use rustc_abi::{Align, HasDataLayout, Primitive, Scalar, Size, WrappingRange};
 use rustc_codegen_ssa::common;
 use rustc_codegen_ssa::traits::*;
 use rustc_hir::LangItem;
+use rustc_hir::attrs::Linkage;
 use rustc_hir::def::DefKind;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
 use rustc_middle::mir::interpret::{
     Allocation, ConstAllocation, ErrorHandled, InitChunk, Pointer, Scalar as InterpScalar,
     read_target_uint,
 };
-use rustc_middle::mir::mono::{Linkage, MonoItem};
+use rustc_middle::mir::mono::MonoItem;
 use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf};
 use rustc_middle::ty::{self, Instance};
 use rustc_middle::{bug, span_bug};
+use rustc_span::Symbol;
 use tracing::{debug, instrument, trace};
 
 use crate::common::CodegenCx;
@@ -191,8 +193,8 @@ fn check_and_apply_linkage<'ll, 'tcx>(
         // linkage and there are no definitions), then
         // `extern_with_linkage_foo` will instead be initialized to
         // zero.
-        let mut real_name = "_rust_extern_with_linkage_".to_string();
-        real_name.push_str(sym);
+        let real_name =
+            format!("_rust_extern_with_linkage_{:016x}_{sym}", cx.tcx.stable_crate_id(LOCAL_CRATE));
         let g2 = cx.define_global(&real_name, llty).unwrap_or_else(|| {
             cx.sess().dcx().emit_fatal(SymbolAlreadyDefined {
                 span: cx.tcx.def_span(def_id),
@@ -330,6 +332,10 @@ impl<'ll> CodegenCx<'ll, '_> {
             }
 
             g
+        } else if let Some(classname) = fn_attrs.objc_class {
+            self.get_objc_classref(classname)
+        } else if let Some(methname) = fn_attrs.objc_selector {
+            self.get_objc_selref(methname)
         } else {
             check_and_apply_linkage(self, fn_attrs, llty, sym, def_id)
         };
@@ -451,6 +457,8 @@ impl<'ll> CodegenCx<'ll, '_> {
             self.statics_to_rauw.borrow_mut().push((g, new_g));
             new_g
         };
+
+        // NOTE: Alignment from attributes has already been applied to the allocation.
         set_global_alignment(self, g, alloc.align);
         llvm::set_initializer(g, v);
 
@@ -540,8 +548,225 @@ impl<'ll> CodegenCx<'ll, '_> {
 
     /// Add a global value to a list to be stored in the `llvm.compiler.used` variable,
     /// an array of ptr.
-    pub(crate) fn add_compiler_used_global(&mut self, global: &'ll Value) {
-        self.compiler_used_statics.push(global);
+    pub(crate) fn add_compiler_used_global(&self, global: &'ll Value) {
+        self.compiler_used_statics.borrow_mut().push(global);
+    }
+
+    // We do our best here to match what Clang does when compiling Objective-C natively.
+    // See Clang's `CGObjCCommonMac::CreateCStringLiteral`:
+    // https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L4134
+    fn define_objc_classname(&self, classname: &str) -> &'ll Value {
+        assert_eq!(self.objc_abi_version(), 1);
+
+        let llval = self.null_terminate_const_bytes(classname.as_bytes());
+        let llty = self.val_ty(llval);
+        let sym = self.generate_local_symbol_name("OBJC_CLASS_NAME_");
+        let g = self.define_global(&sym, llty).unwrap_or_else(|| {
+            bug!("symbol `{}` is already defined", sym);
+        });
+        set_global_alignment(self, g, self.tcx.data_layout.i8_align.abi);
+        llvm::set_initializer(g, llval);
+        llvm::set_linkage(g, llvm::Linkage::PrivateLinkage);
+        llvm::set_section(g, c"__TEXT,__cstring,cstring_literals");
+        llvm::LLVMSetGlobalConstant(g, llvm::TRUE);
+        llvm::LLVMSetUnnamedAddress(g, llvm::UnnamedAddr::Global);
+        self.add_compiler_used_global(g);
+
+        g
+    }
+
+    // We do our best here to match what Clang does when compiling Objective-C natively.
+    // See Clang's `ObjCNonFragileABITypesHelper`:
+    // https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L6052
+    fn get_objc_class_t(&self) -> &'ll Type {
+        if let Some(class_t) = self.objc_class_t.get() {
+            return class_t;
+        }
+
+        assert_eq!(self.objc_abi_version(), 2);
+
+        // struct _class_t {
+        //     struct _class_t* isa;
+        //     struct _class_t* const superclass;
+        //     void* cache;
+        //     IMP* vtable;
+        //     struct class_ro_t* ro;
+        // }
+
+        let class_t = self.type_named_struct("struct._class_t");
+        let els = [self.type_ptr(); 5];
+        let packed = false;
+        self.set_struct_body(class_t, &els, packed);
+
+        self.objc_class_t.set(Some(class_t));
+        class_t
+    }
+
+    // We do our best here to match what Clang does when compiling Objective-C natively. We
+    // deduplicate references within a CGU, but we need a reference definition in each referencing
+    // CGU. All attempts at using external references to a single reference definition result in
+    // linker errors.
+    fn get_objc_classref(&self, classname: Symbol) -> &'ll Value {
+        let mut classrefs = self.objc_classrefs.borrow_mut();
+        if let Some(classref) = classrefs.get(&classname).copied() {
+            return classref;
+        }
+
+        let g = match self.objc_abi_version() {
+            1 => {
+                // See Clang's `CGObjCMac::EmitClassRefFromId`:
+                // https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L5205
+                let llval = self.define_objc_classname(classname.as_str());
+                let llty = self.type_ptr();
+                let sym = self.generate_local_symbol_name("OBJC_CLASS_REFERENCES_");
+                let g = self.define_global(&sym, llty).unwrap_or_else(|| {
+                    bug!("symbol `{}` is already defined", sym);
+                });
+                set_global_alignment(self, g, self.tcx.data_layout.pointer_align().abi);
+                llvm::set_initializer(g, llval);
+                llvm::set_linkage(g, llvm::Linkage::PrivateLinkage);
+                llvm::set_section(g, c"__OBJC,__cls_refs,literal_pointers,no_dead_strip");
+                self.add_compiler_used_global(g);
+                g
+            }
+            2 => {
+                // See Clang's `CGObjCNonFragileABIMac::EmitClassRefFromId`:
+                // https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L7423
+                let llval = {
+                    let extern_sym = format!("OBJC_CLASS_$_{}", classname.as_str());
+                    let extern_llty = self.get_objc_class_t();
+                    self.declare_global(&extern_sym, extern_llty)
+                };
+                let llty = self.type_ptr();
+                let sym = self.generate_local_symbol_name("OBJC_CLASSLIST_REFERENCES_$_");
+                let g = self.define_global(&sym, llty).unwrap_or_else(|| {
+                    bug!("symbol `{}` is already defined", sym);
+                });
+                set_global_alignment(self, g, self.tcx.data_layout.pointer_align().abi);
+                llvm::set_initializer(g, llval);
+                llvm::set_linkage(g, llvm::Linkage::InternalLinkage);
+                llvm::set_section(g, c"__DATA,__objc_classrefs,regular,no_dead_strip");
+                self.add_compiler_used_global(g);
+                g
+            }
+            _ => unreachable!(),
+        };
+
+        classrefs.insert(classname, g);
+        g
+    }
+
+    // We do our best here to match what Clang does when compiling Objective-C natively. We
+    // deduplicate references within a CGU, but we need a reference definition in each referencing
+    // CGU. All attempts at using external references to a single reference definition result in
+    // linker errors.
+    //
+    // Newer versions of Apple Clang generate calls to `@"objc_msgSend$methname"` selector stub
+    // functions. We don't currently do that. The code we generate is closer to what Apple Clang
+    // generates with the `-fno-objc-msgsend-selector-stubs` option.
+    fn get_objc_selref(&self, methname: Symbol) -> &'ll Value {
+        let mut selrefs = self.objc_selrefs.borrow_mut();
+        if let Some(selref) = selrefs.get(&methname).copied() {
+            return selref;
+        }
+
+        let abi_version = self.objc_abi_version();
+
+        // See Clang's `CGObjCCommonMac::CreateCStringLiteral`:
+        // https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L4134
+        let methname_llval = self.null_terminate_const_bytes(methname.as_str().as_bytes());
+        let methname_llty = self.val_ty(methname_llval);
+        let methname_sym = self.generate_local_symbol_name("OBJC_METH_VAR_NAME_");
+        let methname_g = self.define_global(&methname_sym, methname_llty).unwrap_or_else(|| {
+            bug!("symbol `{}` is already defined", methname_sym);
+        });
+        set_global_alignment(self, methname_g, self.tcx.data_layout.i8_align.abi);
+        llvm::set_initializer(methname_g, methname_llval);
+        llvm::set_linkage(methname_g, llvm::Linkage::PrivateLinkage);
+        llvm::set_section(
+            methname_g,
+            match abi_version {
+                1 => c"__TEXT,__cstring,cstring_literals",
+                2 => c"__TEXT,__objc_methname,cstring_literals",
+                _ => unreachable!(),
+            },
+        );
+        llvm::LLVMSetGlobalConstant(methname_g, llvm::TRUE);
+        llvm::LLVMSetUnnamedAddress(methname_g, llvm::UnnamedAddr::Global);
+        self.add_compiler_used_global(methname_g);
+
+        // See Clang's `CGObjCMac::EmitSelectorAddr`:
+        // https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L5243
+        // And Clang's `CGObjCNonFragileABIMac::EmitSelectorAddr`:
+        // https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L7586
+        let selref_llval = methname_g;
+        let selref_llty = self.type_ptr();
+        let selref_sym = self.generate_local_symbol_name("OBJC_SELECTOR_REFERENCES_");
+        let selref_g = self.define_global(&selref_sym, selref_llty).unwrap_or_else(|| {
+            bug!("symbol `{}` is already defined", selref_sym);
+        });
+        set_global_alignment(self, selref_g, self.tcx.data_layout.pointer_align().abi);
+        llvm::set_initializer(selref_g, selref_llval);
+        llvm::set_externally_initialized(selref_g, true);
+        llvm::set_linkage(
+            selref_g,
+            match abi_version {
+                1 => llvm::Linkage::PrivateLinkage,
+                2 => llvm::Linkage::InternalLinkage,
+                _ => unreachable!(),
+            },
+        );
+        llvm::set_section(
+            selref_g,
+            match abi_version {
+                1 => c"__OBJC,__message_refs,literal_pointers,no_dead_strip",
+                2 => c"__DATA,__objc_selrefs,literal_pointers,no_dead_strip",
+                _ => unreachable!(),
+            },
+        );
+        self.add_compiler_used_global(selref_g);
+
+        selrefs.insert(methname, selref_g);
+        selref_g
+    }
+
+    // We do our best here to match what Clang does when compiling Objective-C natively.
+    // See Clang's `ObjCTypesHelper`:
+    // https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L5936
+    // And Clang's `CGObjCMac::EmitModuleInfo`:
+    // https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L5151
+    pub(crate) fn define_objc_module_info(&mut self) {
+        assert_eq!(self.objc_abi_version(), 1);
+
+        // struct _objc_module {
+        //     long version;                // Hardcoded to 7 in Clang.
+        //     long size;                   // sizeof(struct _objc_module)
+        //     char* name;                  // Hardcoded to classname "" in Clang.
+        //     struct _objc_symtab* symtab; // Null without class or category definitions.
+        //  }
+
+        let llty = self.type_named_struct("struct._objc_module");
+        let i32_llty = self.type_i32();
+        let ptr_llty = self.type_ptr();
+        let packed = false;
+        self.set_struct_body(llty, &[i32_llty, i32_llty, ptr_llty, ptr_llty], packed);
+
+        let version = self.const_uint(i32_llty, 7);
+        let size = self.const_uint(i32_llty, 16);
+        let name = self.define_objc_classname("");
+        let symtab = self.const_null(ptr_llty);
+        let llval = crate::common::named_struct(llty, &[version, size, name, symtab]);
+
+        let sym = "OBJC_MODULES";
+        let g = self.define_global(&sym, llty).unwrap_or_else(|| {
+            bug!("symbol `{}` is already defined", sym);
+        });
+        set_global_alignment(self, g, self.tcx.data_layout.pointer_align().abi);
+        llvm::set_initializer(g, llval);
+        llvm::set_linkage(g, llvm::Linkage::PrivateLinkage);
+        llvm::set_section(g, c"__OBJC,__module_info,regular,no_dead_strip");
+
+        self.add_compiler_used_global(g);
     }
 }