[llvm-branch-commits] [lld] [lld][MachO] Support Objective-C class stubs (PR #219744)

Kyungwoo Lee via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Tue Sep 1 17:54:26 PDT 2026


https://github.com/kyulee-com updated https://github.com/llvm/llvm-project/pull/219744

>From 10fc6c20a0847a165e6ca22e6f8db36b2f585412 Mon Sep 17 00:00:00 2001
From: Kyungwoo Lee <kyulee at meta.com>
Date: Sat, 29 Aug 2026 15:40:39 -0700
Subject: [PATCH] [lld][MachO] Support Objective-C class stubs

Teach Mach-O objc stubs to synthesize class-message stubs that load the class object, selector, and objc_msgSend target.

lld already supports the Apple clang _objc_msgSend$<selector> stub form, even though upstream clang does not currently expose a driver or cc1 flag for emitting it. Apple clang also emits _objc_msgSendClass$<selector>$_OBJC_CLASS_$_<class>; handling that form completes the existing selector-stub support.

Cover local classes, dylib classes, archives, dynamic lookup via -U, missing class symbols, malformed names, unsupported architectures, and dead stripping.
---
 lld/MachO/Arch/ARM64.cpp                      |  94 +++++
 lld/MachO/Driver.cpp                          |  40 ++-
 lld/MachO/MarkLive.cpp                        |   4 +
 lld/MachO/SyntheticSections.cpp               | 125 ++++++-
 lld/MachO/SyntheticSections.h                 |  21 +-
 lld/MachO/Target.h                            |   8 +
 lld/docs/ReleaseNotes.md                      |   4 +
 lld/test/MachO/arm64-objc-class-stubs-dead.s  |  82 +++++
 lld/test/MachO/arm64-objc-class-stubs.s       | 332 ++++++++++++++++++
 lld/test/MachO/objc-class-stubs-unsupported.s |  66 ++++
 10 files changed, 754 insertions(+), 22 deletions(-)
 create mode 100644 lld/test/MachO/arm64-objc-class-stubs-dead.s
 create mode 100644 lld/test/MachO/arm64-objc-class-stubs.s
 create mode 100644 lld/test/MachO/objc-class-stubs-unsupported.s

diff --git a/lld/MachO/Arch/ARM64.cpp b/lld/MachO/Arch/ARM64.cpp
index 7acf48cbbf123..49756c170dd8d 100644
--- a/lld/MachO/Arch/ARM64.cpp
+++ b/lld/MachO/Arch/ARM64.cpp
@@ -33,6 +33,13 @@ struct ARM64 : ARM64Common {
   void writeObjCMsgSendStub(uint8_t *buf, Symbol *sym, uint64_t stubsAddr,
                             uint64_t &stubOffset, uint64_t selrefVA,
                             Symbol *objcMsgSend) const override;
+  void writeObjCMsgSendClassStub(uint8_t *buf, Symbol *sym, uint64_t stubsAddr,
+                                 uint64_t &stubOffset, uint64_t selrefVA,
+                                 Symbol *classSym,
+                                 Symbol *objcMsgSend) const override;
+  bool supportsObjCClassStubs() const override {
+    return config->arch() == AK_arm64;
+  }
   void populateThunk(InputSection *thunk, Symbol *funcSym,
                      int64_t addend) override;
 
@@ -121,6 +128,27 @@ static constexpr uint32_t objcStubsSmallCode[] = {
     0x14000000, // b     _objc_msgSend
 };
 
+static constexpr uint32_t objcClassStubsFastCode[] = {
+    0x90000000, // adrp  x0, _OBJC_CLASS_$_Foo at page
+                // The ldr below is patched to add for locally defined classes.
+    0xf9400000, // ldr   x0, [x0, _OBJC_CLASS_$_Foo at pageoff]
+    0x90000001, // adrp  x1, __objc_selrefs at page
+    0xf9400021, // ldr   x1, [x1, @selector("foo")@pageoff]
+    0x90000010, // adrp  x16, _got at page
+    0xf9400210, // ldr   x16, [x16, _objc_msgSend at pageoff]
+    0xd61f0200, // br    x16
+    0xd4200020, // brk   #0x1
+};
+
+static constexpr uint32_t objcClassStubsSmallCode[] = {
+    0x90000000, // adrp  x0, _OBJC_CLASS_$_Foo at page
+                // The ldr below is patched to add for locally defined classes.
+    0xf9400000, // ldr   x0, [x0, _OBJC_CLASS_$_Foo at pageoff]
+    0x90000001, // adrp  x1, __objc_selrefs at page
+    0xf9400021, // ldr   x1, [x1, @selector("foo")@pageoff]
+    0x14000000, // b     _objc_msgSend
+};
+
 void ARM64::writeObjCMsgSendStub(uint8_t *buf, Symbol *sym, uint64_t stubsAddr,
                                  uint64_t &stubOffset, uint64_t selrefVA,
                                  Symbol *objcMsgSend) const {
@@ -152,6 +180,70 @@ void ARM64::writeObjCMsgSendStub(uint8_t *buf, Symbol *sym, uint64_t stubsAddr,
   stubOffset += objcStubSize;
 }
 
+void ARM64::writeObjCMsgSendClassStub(uint8_t *buf, Symbol *stubSym,
+                                      uint64_t stubsAddr, uint64_t &stubOffset,
+                                      uint64_t selrefVA, Symbol *classSym,
+                                      Symbol *objcMsgSend) const {
+  SymbolDiagnostic d = {stubSym, stubSym->getName()};
+  auto *buf32 = reinterpret_cast<uint32_t *>(buf);
+
+  auto pcPageBits = [stubsAddr, stubOffset](int i) {
+    return pageBits(stubsAddr + stubOffset + i * sizeof(uint32_t));
+  };
+  auto writeClassLoad = [&](const uint32_t *code) {
+    uint64_t classVA;
+    uint32_t pageOffCode = code[1];
+    if (auto *defined = dyn_cast<Defined>(classSym)) {
+      classVA = defined->getVA();
+      pageOffCode = 0x91000000; // add x0, x0, _OBJC_CLASS_$_Foo at pageoff
+    } else {
+      classVA = in.got->addr + classSym->gotIndex * LP64::wordSize;
+    }
+    encodePage21(&buf32[0], d, code[0], pageBits(classVA) - pcPageBits(0));
+    encodePageOff12(&buf32[1], d, pageOffCode, classVA);
+  };
+
+  uint64_t objcMsgSendAddr;
+  uint64_t objcMsgSendIndex;
+
+  if (config->objcStubsMode == ObjCStubsMode::fast) {
+    writeClassLoad(objcClassStubsFastCode);
+    encodePage21(&buf32[2], d, objcClassStubsFastCode[2],
+                 pageBits(selrefVA) - pcPageBits(2));
+    encodePageOff12(&buf32[3], d, objcClassStubsFastCode[3], selrefVA);
+    objcMsgSendAddr = in.got->addr;
+    objcMsgSendIndex = objcMsgSend->gotIndex;
+    uint64_t gotOffset = objcMsgSendIndex * LP64::wordSize;
+    encodePage21(&buf32[4], d, objcClassStubsFastCode[4],
+                 pageBits(objcMsgSendAddr + gotOffset) - pcPageBits(4));
+    encodePageOff12(&buf32[5], d, objcClassStubsFastCode[5],
+                    objcMsgSendAddr + gotOffset);
+    buf32[6] = objcClassStubsFastCode[6];
+    buf32[7] = objcClassStubsFastCode[7];
+    stubOffset += target->objcClassStubsFastSize;
+    return;
+  }
+
+  assert(config->objcStubsMode == ObjCStubsMode::small);
+  writeClassLoad(objcClassStubsSmallCode);
+  encodePage21(&buf32[2], d, objcClassStubsSmallCode[2],
+               pageBits(selrefVA) - pcPageBits(2));
+  encodePageOff12(&buf32[3], d, objcClassStubsSmallCode[3], selrefVA);
+  if (auto *defined = dyn_cast<Defined>(objcMsgSend)) {
+    objcMsgSendAddr = defined->getVA();
+    objcMsgSendIndex = 0;
+  } else {
+    objcMsgSendAddr = in.stubs->addr;
+    objcMsgSendIndex = objcMsgSend->stubsIndex;
+  }
+  uint64_t msgSendStubVA =
+      objcMsgSendAddr + objcMsgSendIndex * target->stubSize;
+  uint64_t pcVA = stubsAddr + stubOffset + 4 * sizeof(uint32_t);
+  encodeBranch26(&buf32[4], {nullptr, "objc_msgSend class stub"},
+                 objcClassStubsSmallCode[4], msgSendStubVA - pcVA);
+  stubOffset += target->objcClassStubsSmallSize;
+}
+
 // A thunk is the relaxed variation of stubCode. We don't need the
 // extra indirection through a lazy pointer because the target address
 // is known at link time.
@@ -215,6 +307,8 @@ ARM64::ARM64() : ARM64Common(LP64()) {
   objcStubsFastAlignment = 32;
   objcStubsSmallSize = sizeof(objcStubsSmallCode);
   objcStubsSmallAlignment = 4;
+  objcClassStubsFastSize = sizeof(objcClassStubsFastCode);
+  objcClassStubsSmallSize = sizeof(objcClassStubsSmallCode);
 
   // Branch immediate is two's complement 26 bits, which is implicitly
   // multiplied by 4 (since all functions are 4-aligned: The branch range
diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp
index b05519f3a8c11..6ad9a7a04d426 100644
--- a/lld/MachO/Driver.cpp
+++ b/lld/MachO/Driver.cpp
@@ -1604,13 +1604,41 @@ static void foldIdenticalLiterals() {
   in.wordLiteralSection->finalizeContents();
 }
 
-static void addSynthenticMethnames() {
+static void prepareObjCStubs() {
   std::string &data = *make<std::string>();
   llvm::raw_string_ostream os(data);
-  for (Symbol *sym : symtab->getSymbols())
-    if (isa<Undefined>(sym))
-      if (ObjCStubsSection::isObjCStubSymbol(sym))
-        os << ObjCStubsSection::getMethname(sym) << '\0';
+  // This loop may add class symbols to the symbol table, so avoid range-for
+  // over the backing vector.
+  for (size_t i = 0; i < symtab->getSymbols().size(); ++i) {
+    Symbol *sym = symtab->getSymbols()[i];
+    if (!isa<Undefined>(sym))
+      continue;
+
+    if (ObjCStubsSection::isObjCMsgSendStubSymbol(sym)) {
+      StringRef selectorName = ObjCStubsSection::getMethname(sym);
+      os << selectorName << '\0';
+    } else if (ObjCStubsSection::isObjCClassStubSymbol(sym)) {
+      std::optional<ObjCStubsSection::ObjCClassStubNames> parsed =
+          ObjCStubsSection::parseObjCClassStubSymbol(sym);
+      if (!parsed)
+        continue;
+
+      os << parsed->selectorName << '\0';
+      if (!target->supportsObjCClassStubs())
+        continue;
+
+      Symbol *classSym = symtab->find(parsed->classSymbolName);
+      bool needsUndefinedClassRef =
+          !classSym || isa<LazyArchive>(classSym) || isa<LazyObject>(classSym);
+      // Create an undefined reference before markLive() only when it may trigger
+      // archive extraction. Existing dylib symbols are marked referenced later
+      // if the class stub survives dead stripping.
+      if (needsUndefinedClassRef)
+        classSym = symtab->addUndefined(parsed->classSymbolName,
+                                        /*file=*/nullptr, /*isWeakRef=*/false);
+      in.objcStubs->recordClassSymbol(sym, classSym);
+    }
+  }
 
   if (data.empty())
     return;
@@ -2470,7 +2498,7 @@ bool link(ArrayRef<const char *> argsArr, llvm::raw_ostream &stdoutOS,
     if (config->thinLTOIndexOnly || config->emitLLVM)
       return errorCount() == 0;
 
-    addSynthenticMethnames();
+    prepareObjCStubs();
 
     // LTO may emit a non-hidden (extern) object file symbol even if the
     // corresponding bitcode symbol is hidden. In particular, this happens for
diff --git a/lld/MachO/MarkLive.cpp b/lld/MachO/MarkLive.cpp
index a51c800bf4ef1..5d4c4efd0e3c4 100644
--- a/lld/MachO/MarkLive.cpp
+++ b/lld/MachO/MarkLive.cpp
@@ -11,6 +11,7 @@
 #include "OutputSegment.h"
 #include "SymbolTable.h"
 #include "Symbols.h"
+#include "SyntheticSections.h"
 #include "UnwindInfoSection.h"
 
 #include "lld/Common/ErrorHandler.h"
@@ -107,6 +108,9 @@ void MarkLiveImpl<RecordWhyLive>::addSym(
   if constexpr (RecordWhyLive)
     if (!config->whyLive.empty() && config->whyLive.match(s->getName()))
       printWhyLive(s, prev);
+  if (ObjCStubsSection::isObjCClassStubSymbol(s))
+    if (auto *classSym = in.objcStubs->lookupClassSymbol(s))
+      addSym(classSym, prev);
   if (auto *d = dyn_cast<Defined>(s)) {
     if (d->isec())
       enqueue(d->isec(), d->value, prev);
diff --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp
index bd39f49ba09e6..6882b30649a90 100644
--- a/lld/MachO/SyntheticSections.cpp
+++ b/lld/MachO/SyntheticSections.cpp
@@ -888,29 +888,116 @@ ObjCStubsSection::ObjCStubsSection()
               : target->objcStubsSmallAlignment;
 }
 
-bool ObjCStubsSection::isObjCStubSymbol(Symbol *sym) {
+bool ObjCStubsSection::isObjCMsgSendStubSymbol(Symbol *sym) {
   return sym->getName().starts_with(objcMsgSendStubPrefix);
 }
 
+bool ObjCStubsSection::isObjCClassStubSymbol(Symbol *sym) {
+  return sym->getName().starts_with(objcMsgSendClassStubPrefix);
+}
+
+bool ObjCStubsSection::isObjCStubSymbol(Symbol *sym) {
+  return isObjCMsgSendStubSymbol(sym) || isObjCClassStubSymbol(sym);
+}
+
 StringRef ObjCStubsSection::getMethname(Symbol *sym) {
   assert(isObjCStubSymbol(sym) && "not an objc stub");
-  auto name = sym->getName();
-  return name.drop_front(objcMsgSendStubPrefix.size());
+  if (isObjCMsgSendStubSymbol(sym))
+    return sym->getName().drop_front(objcMsgSendStubPrefix.size());
+
+  assert(isObjCClassStubSymbol(sym) && "not an objc class stub");
+  std::optional<ObjCClassStubNames> parsed = parseObjCClassStubSymbol(sym);
+  assert(parsed && "malformed objc class stub");
+  return parsed->selectorName;
+}
+
+std::optional<ObjCStubsSection::ObjCClassStubNames>
+ObjCStubsSection::parseObjCClassStubSymbol(Symbol *sym) {
+  assert(isObjCClassStubSymbol(sym) && "not an objc class stub");
+  StringRef name = sym->getName().drop_front(objcMsgSendClassStubPrefix.size());
+  // For _objc_msgSendClass$alloc$_OBJC_CLASS_$_Foo, return selectorName
+  // "alloc" and classSymbolName "_OBJC_CLASS_$_Foo".
+  auto [selectorName, classSymbolName] = name.split('$');
+  if (selectorName.empty() || classSymbolName.empty() ||
+      !classSymbolName.starts_with(objcClassSymbolPrefix))
+    return std::nullopt;
+  return ObjCClassStubNames{selectorName, classSymbolName};
+}
+
+void ObjCStubsSection::recordClassSymbol(Symbol *stubSym, Symbol *classSym) {
+  // SymbolTable updates symbols in place with replaceSymbol(), so this pointer
+  // remains valid if an Undefined later becomes a DylibSymbol or Defined.
+  classSymbols[stubSym] = classSym;
+}
+
+Symbol *ObjCStubsSection::lookupClassSymbol(Symbol *stubSym) const {
+  return classSymbols.lookup(stubSym);
 }
 
-size_t ObjCStubsSection::getStubSize() const {
-  return config->objcStubsMode == ObjCStubsMode::fast
-             ? target->objcStubsFastSize
-             : target->objcStubsSmallSize;
+size_t ObjCStubsSection::getStubSize(Symbol *sym) const {
+  if (config->objcStubsMode == ObjCStubsMode::fast)
+    return isObjCClassStubSymbol(sym) ? target->objcClassStubsFastSize
+                                      : target->objcStubsFastSize;
+  return isObjCClassStubSymbol(sym) ? target->objcClassStubsSmallSize
+                                    : target->objcStubsSmallSize;
 }
 
 void ObjCStubsSection::addEntry(Symbol *sym) {
-  StringRef methname = getMethname(sym);
-  // We create a selref entry for each unique methname.
-  if (!ObjCSelRefsHelper::getSelRef(methname))
-    ObjCSelRefsHelper::makeSelRef(methname);
+  // Replace invalid stubs to avoid follow-on undefined-symbol diagnostics.
+  auto replaceWithEmptyStub = [&] {
+    replaceSymbol<Defined>(
+        sym, sym->getName(), nullptr, isec, /*value=*/stubsSize, /*size=*/0,
+        /*isWeakDef=*/false, /*isExternal=*/true, /*isPrivateExtern=*/true,
+        /*includeInSymtab=*/true, /*isReferencedDynamically=*/false,
+        /*noDeadStrip=*/false);
+  };
+
+  StringRef selectorName;
+  Symbol *classSym = nullptr;
+  if (isObjCClassStubSymbol(sym)) {
+    if (!target->supportsObjCClassStubs()) {
+      error("objc class stubs are not supported for " +
+            getArchitectureName(config->arch()));
+      replaceWithEmptyStub();
+      return;
+    }
+    std::optional<ObjCClassStubNames> parsed = parseObjCClassStubSymbol(sym);
+    if (!parsed) {
+      error("malformed objc class stub symbol " + sym->getName() +
+            "; expected " + objcMsgSendClassStubPrefix + "<selector>" +
+            "$" + objcClassSymbolPrefix + "<class>");
+      replaceWithEmptyStub();
+      return;
+    }
+    selectorName = parsed->selectorName;
+    classSym = lookupClassSymbol(sym);
+    if (!classSym) {
+      error("objc class stub symbol " + sym->getName() +
+            " references missing class symbol " + parsed->classSymbolName);
+      replaceWithEmptyStub();
+      return;
+    }
+    if (auto *undefined = dyn_cast<Undefined>(classSym)) {
+      treatUndefinedSymbol(*undefined, "objc class stub");
+      if (isa<Undefined>(classSym)) {
+        replaceWithEmptyStub();
+        return;
+      }
+    }
+    if (auto *dysym = dyn_cast<DylibSymbol>(classSym)) {
+      dysym->reference(RefState::Strong);
+      in.got->addEntry(dysym);
+    }
+    classSym->used = true;
+  } else {
+    selectorName = getMethname(sym);
+  }
+
+  size_t stubSize = getStubSize(sym);
+  // We create a selref entry for each unique selector.
+  if (!ObjCSelRefsHelper::getSelRef(selectorName))
+    ObjCSelRefsHelper::makeSelRef(selectorName);
 
-  size_t stubSize = getStubSize();
   Defined *newSym = replaceSymbol<Defined>(
       sym, sym->getName(), nullptr, isec,
       /*value=*/stubsSize,
@@ -958,7 +1045,7 @@ void ObjCStubsSection::sortSymbols(
   size_t stubOffset = 0;
   for (Defined *sym : symbols) {
     sym->value = stubOffset;
-    stubOffset += getStubSize();
+    stubOffset += getStubSize(sym);
   }
 }
 
@@ -969,8 +1056,16 @@ void ObjCStubsSection::writeTo(uint8_t *buf) const {
     InputSection *selRef = ObjCSelRefsHelper::getSelRef(methname);
     assert(selRef != nullptr && "no selref for methname");
     auto selrefAddr = selRef->getVA(0);
-    target->writeObjCMsgSendStub(buf + stubOffset, sym, in.objcStubs->addr,
-                                 stubOffset, selrefAddr, objcMsgSend);
+    if (isObjCClassStubSymbol(sym)) {
+      Symbol *classSym = classSymbols.lookup(sym);
+      assert(classSym != nullptr && "no class symbol for objc class stub");
+      target->writeObjCMsgSendClassStub(buf + stubOffset, sym,
+                                        in.objcStubs->addr, stubOffset,
+                                        selrefAddr, classSym, objcMsgSend);
+    } else {
+      target->writeObjCMsgSendStub(buf + stubOffset, sym, in.objcStubs->addr,
+                                   stubOffset, selrefAddr, objcMsgSend);
+    }
   }
 }
 
diff --git a/lld/MachO/SyntheticSections.h b/lld/MachO/SyntheticSections.h
index 6642ed64112cf..a9ff0cddc2b17 100644
--- a/lld/MachO/SyntheticSections.h
+++ b/lld/MachO/SyntheticSections.h
@@ -24,6 +24,8 @@
 #include "llvm/Support/MathExtras.h"
 #include "llvm/Support/raw_ostream.h"
 
+#include <optional>
+
 namespace llvm {
 class DWARFUnit;
 } // namespace llvm
@@ -343,17 +345,34 @@ class ObjCStubsSection final : public SyntheticSection {
   void setUp();
 
   static constexpr llvm::StringLiteral objcMsgSendStubPrefix = "_objc_msgSend$";
+  static constexpr llvm::StringLiteral objcMsgSendClassStubPrefix =
+      "_objc_msgSendClass$";
+  static constexpr llvm::StringLiteral objcClassSymbolPrefix =
+      "_OBJC_CLASS_$_";
+  // Plain selector stub: _objc_msgSend$<selector>.
+  static bool isObjCMsgSendStubSymbol(Symbol *sym);
+  // Class-message stub: _objc_msgSendClass$<selector>$_OBJC_CLASS_$_<class>.
+  static bool isObjCClassStubSymbol(Symbol *sym);
+  // Any symbol handled by ObjCStubsSection.
   static bool isObjCStubSymbol(Symbol *sym);
   static StringRef getMethname(Symbol *sym);
+  struct ObjCClassStubNames {
+    StringRef selectorName;
+    StringRef classSymbolName;
+  };
+  static std::optional<ObjCClassStubNames> parseObjCClassStubSymbol(Symbol *sym);
+  void recordClassSymbol(Symbol *stubSym, Symbol *classSym);
+  Symbol *lookupClassSymbol(Symbol *stubSym) const;
 
   /// Stably sort the stubs by \p priorities and reassign their offsets. Must
   /// run before addresses are assigned.
   void sortSymbols(const llvm::DenseMap<const Symbol *, int> &priorities);
 
 private:
-  size_t getStubSize() const;
+  size_t getStubSize(Symbol *sym) const;
 
   std::vector<Defined *> symbols;
+  llvm::DenseMap<Symbol *, Symbol *> classSymbols;
   // Total byte size of all stubs added so far.
   size_t stubsSize = 0;
   Symbol *objcMsgSend = nullptr;
diff --git a/lld/MachO/Target.h b/lld/MachO/Target.h
index 0c7c0c3817c97..4165b159c633f 100644
--- a/lld/MachO/Target.h
+++ b/lld/MachO/Target.h
@@ -73,6 +73,12 @@ class TargetInfo {
                                     uint64_t stubsAddr, uint64_t &stubOffset,
                                     uint64_t selrefVA,
                                     Symbol *objcMsgSend) const = 0;
+  virtual void writeObjCMsgSendClassStub(uint8_t *, Symbol *, uint64_t,
+                                         uint64_t &, uint64_t, Symbol *,
+                                         Symbol *) const {
+    llvm_unreachable("target does not support objc class stubs");
+  }
+  virtual bool supportsObjCClassStubs() const { return false; }
 
   // Init 'thunk' so that it be a direct jump to 'branchTarget'.
   virtual void initICFSafeThunkBody(InputSection *thunk,
@@ -136,6 +142,8 @@ class TargetInfo {
   size_t stubHelperEntrySize;
   size_t objcStubsFastSize;
   size_t objcStubsSmallSize;
+  size_t objcClassStubsFastSize = 0;
+  size_t objcClassStubsSmallSize = 0;
   size_t objcStubsFastAlignment;
   size_t objcStubsSmallAlignment;
   uint8_t p2WordSize;
diff --git a/lld/docs/ReleaseNotes.md b/lld/docs/ReleaseNotes.md
index 00c9f5c85af8f..1df382ec56a52 100644
--- a/lld/docs/ReleaseNotes.md
+++ b/lld/docs/ReleaseNotes.md
@@ -40,6 +40,10 @@ from the [LLVM releases web site](https://llvm.org/releases/).
 * `__objc_stubs` entries are now ordered by the priority of the sections that
   call them, so that stubs reached from prioritized code are laid out together.
   This applies whenever section priorities exist, such as with `-order_file`.
+* Added support for Objective-C class-message stubs
+  (`_objc_msgSendClass$<selector>$_OBJC_CLASS_$_<class>`), which load the
+  class object, selector, and `objc_msgSend` target. Supported on arm64; other
+  architectures report an error.
 
 ### WebAssembly Improvements
 
diff --git a/lld/test/MachO/arm64-objc-class-stubs-dead.s b/lld/test/MachO/arm64-objc-class-stubs-dead.s
new file mode 100644
index 0000000000000..501dbea308724
--- /dev/null
+++ b/lld/test/MachO/arm64-objc-class-stubs-dead.s
@@ -0,0 +1,82 @@
+# REQUIRES: aarch64
+
+# Tests that -dead_strip keeps only live ObjC class stubs and does not keep dead
+# class definitions or dylib loads alive.
+
+# RUN: rm -rf %t && split-file %s %t
+
+# Check that only the live class-stub dependency survives dead stripping.
+# RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %t/main.s -o %t/main.o
+# RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %t/dylib.s \
+# RUN:   -o %t/dylib.o
+# RUN: %lld -arch arm64 -dylib -install_name @executable_path/libdead.dylib \
+# RUN:   -o %t/libdead.dylib %t/dylib.o
+# RUN: %lld -arch arm64 -lSystem -dead_strip -dead_strip_dylibs \
+# RUN:   -o %t.out %t/main.o %t/libdead.dylib -U _objc_msgSend \
+# RUN:   -objc_stubs_small
+# RUN: llvm-objdump --no-leading-addr --no-show-raw-insn --section=__TEXT,__objc_stubs \
+# RUN:   --macho %t.out | FileCheck %s --check-prefix=STUBS
+# RUN: llvm-nm %t.out | FileCheck %s --check-prefix=SYMS
+# RUN: llvm-otool -L %t.out | FileCheck %s --check-prefix=LOAD
+
+# STUBS:      Contents of (__TEXT,__objc_stubs) section
+# STUBS-NEXT: _objc_msgSendClass$live$_OBJC_CLASS_$_LiveClass:
+# STUBS-NOT:  _objc_msgSendClass$dead$_OBJC_CLASS_$_DeadClass:
+# STUBS-NOT:  _objc_msgSendClass$missing$_OBJC_CLASS_$_NeverDefined:
+# STUBS-NOT:  _objc_msgSendClass$dylib$_OBJC_CLASS_$_DylibClass:
+
+# SYMS-NOT: _OBJC_CLASS_$_DeadClass
+# SYMS-NOT: _OBJC_CLASS_$_NeverDefined
+# SYMS:     _OBJC_CLASS_$_LiveClass
+# SYMS-NOT: _OBJC_CLASS_$_DeadClass
+# SYMS-NOT: _OBJC_CLASS_$_NeverDefined
+
+# LOAD-NOT: libdead.dylib
+# LOAD:     /usr/lib/libSystem.dylib
+# LOAD-NOT: libdead.dylib
+
+#--- main.s
+# Contains one live class stub and several dead class-stub references.
+.text
+.globl _main
+_main:
+  bl _live
+  ret
+
+.globl _live
+_live:
+  bl _objc_msgSendClass$live$_OBJC_CLASS_$_LiveClass
+  ret
+
+.globl _dead
+_dead:
+  bl _objc_msgSendClass$dead$_OBJC_CLASS_$_DeadClass
+  ret
+
+.globl _missing
+_missing:
+  bl _objc_msgSendClass$missing$_OBJC_CLASS_$_NeverDefined
+  ret
+
+.globl _dylibdead
+_dylibdead:
+  bl _objc_msgSendClass$dylib$_OBJC_CLASS_$_DylibClass
+  ret
+
+.data
+.globl _OBJC_CLASS_$_LiveClass
+_OBJC_CLASS_$_LiveClass:
+  .quad 0
+
+.globl _OBJC_CLASS_$_DeadClass
+_OBJC_CLASS_$_DeadClass:
+  .quad 0
+
+.subsections_via_symbols
+
+#--- dylib.s
+# Provides a dylib class referenced only by dead code.
+.data
+.globl _OBJC_CLASS_$_DylibClass
+_OBJC_CLASS_$_DylibClass:
+  .quad 0
diff --git a/lld/test/MachO/arm64-objc-class-stubs.s b/lld/test/MachO/arm64-objc-class-stubs.s
new file mode 100644
index 0000000000000..c453b01b790d1
--- /dev/null
+++ b/lld/test/MachO/arm64-objc-class-stubs.s
@@ -0,0 +1,332 @@
+# REQUIRES: aarch64
+
+# Tests arm64 ObjC class stub emission for fast/small stubs, local/dylib/archive
+# classes, autolinked archives, dynamic lookup, malformed names, and missing classes.
+
+# RUN: rm -rf %t && split-file %s %t
+
+# Check fast and small stubs for regular, local class, and dylib class calls.
+# RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %t/main.s -o %t/main.o
+# RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %t/external.s -o %t/external.o
+# RUN: %lld -arch arm64 -dylib -install_name @executable_path/libexternal.dylib \
+# RUN:   -o %t/libexternal.dylib %t/external.o
+# RUN: %lld -arch arm64 -lSystem -o %t/fast.out %t/main.o \
+# RUN:   %t/libexternal.dylib -objc_stubs_fast
+# RUN: llvm-objdump --no-leading-addr --no-show-raw-insn --section=__TEXT,__objc_stubs \
+# RUN:   --macho %t/fast.out | FileCheck %s --check-prefix=FAST
+# RUN: %lld -arch arm64 -lSystem -o %t/small.out %t/main.o \
+# RUN:   %t/libexternal.dylib -objc_stubs_small
+# RUN: llvm-objdump --no-leading-addr --no-show-raw-insn --section=__TEXT,__objc_stubs \
+# RUN:   --macho %t/small.out | FileCheck %s --check-prefix=SMALL
+
+# Check archive extraction through class-stub references.
+# RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %t/archive-main.s \
+# RUN:   -o %t/archive-main.o
+# RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %t/archive-class.s \
+# RUN:   -o %t/archive-class.o
+# RUN: llvm-ar rcs %t/libarchive.a %t/archive-class.o
+# RUN: %lld -arch arm64 -lSystem -o %t/archive.out %t/archive-main.o \
+# RUN:   %t/libarchive.a -objc_stubs_fast -U _objc_msgSend
+# RUN: llvm-objdump --no-leading-addr --no-show-raw-insn --section=__TEXT,__objc_stubs \
+# RUN:   --macho %t/archive.out | FileCheck %s --check-prefix=ARCHIVE
+# RUN: llvm-nm %t/archive.out | FileCheck %s --check-prefix=ARCHIVE-SYMS
+# RUN: %lld -arch arm64 -lSystem -o %t/start-lib.out %t/archive-main.o \
+# RUN:   --start-lib %t/archive-class.o --end-lib -objc_stubs_fast \
+# RUN:   -U _objc_msgSend
+# RUN: llvm-objdump --no-leading-addr --no-show-raw-insn --section=__TEXT,__objc_stubs \
+# RUN:   --macho %t/start-lib.out | FileCheck %s --check-prefix=ARCHIVE
+# RUN: llvm-nm %t/start-lib.out | FileCheck %s --check-prefix=ARCHIVE-SYMS
+
+# Check autolink extraction when the archive member defines the class.
+# RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %t/autolink-main-a.s \
+# RUN:   -o %t/autolink-main-a.o
+# RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %t/autolink-dep-a.s \
+# RUN:   -o %t/autolink-dep-a.o
+# RUN: llvm-ar rcs %t/libautolinka.a %t/autolink-dep-a.o
+# RUN: %lld -arch arm64 -lSystem -o %t/autolink-a.out \
+# RUN:   %t/autolink-main-a.o -L%t -objc_stubs_fast -U _objc_msgSend
+# RUN: llvm-objdump --no-leading-addr --no-show-raw-insn --section=__TEXT,__objc_stubs \
+# RUN:   --macho %t/autolink-a.out | FileCheck %s --check-prefix=AUTOLINK-A
+
+# Check autolink extraction when the class is already known.
+# RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %t/autolink-main-b.s \
+# RUN:   -o %t/autolink-main-b.o
+# RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %t/autolink-dep-b.s \
+# RUN:   -o %t/autolink-dep-b.o
+# RUN: llvm-ar rcs %t/libautolinkb.a %t/autolink-dep-b.o
+# RUN: %lld -arch arm64 -lSystem -dead_strip -o %t/autolink-b.out \
+# RUN:   %t/autolink-main-b.o -L%t -objc_stubs_fast -U _objc_msgSend
+# RUN: llvm-objdump --no-leading-addr --no-show-raw-insn --section=__TEXT,__objc_stubs \
+# RUN:   --macho %t/autolink-b.out | FileCheck %s --check-prefix=AUTOLINK-B
+# RUN: llvm-nm %t/autolink-b.out | FileCheck %s --check-prefix=AUTOLINK-B-SYMS
+
+# Check class stubs for dynamic class symbols.
+# RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %t/dynamic.s \
+# RUN:   -o %t/dynamic.o
+# RUN: %lld -arch arm64 -lSystem -o %t/dynamic.out %t/dynamic.o \
+# RUN:   -objc_stubs_fast -U '_OBJC_CLASS_$_DynamicClass' -U _objc_msgSend
+# RUN: llvm-objdump --no-leading-addr --no-show-raw-insn --section=__TEXT,__objc_stubs \
+# RUN:   --macho %t/dynamic.out | FileCheck %s --check-prefix=DYNAMIC
+# RUN: %lld -arch arm64 -lSystem -o %t/dynamic-lookup.out %t/dynamic.o \
+# RUN:   -objc_stubs_fast -undefined dynamic_lookup
+# RUN: llvm-objdump --no-leading-addr --no-show-raw-insn --section=__TEXT,__objc_stubs \
+# RUN:   --macho %t/dynamic-lookup.out | FileCheck %s --check-prefix=DYNAMIC
+
+# Check diagnostics for missing class symbols.
+# RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %t/missing.s \
+# RUN:   -o %t/missing.o
+# RUN: not %lld -arch arm64 -lSystem -o /dev/null %t/missing.o \
+# RUN:   -objc_stubs_fast 2>&1 | FileCheck %s --check-prefix=MISSING
+
+# Check diagnostics for malformed class-stub symbol names.
+# RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %t/malformed.s \
+# RUN:   -o %t/malformed.o
+# RUN: not %lld -arch arm64 -lSystem -o /dev/null %t/malformed.o \
+# RUN:   -objc_stubs_fast 2>&1 | FileCheck %s --check-prefix=MALFORMED
+
+# FAST:      Contents of (__TEXT,__objc_stubs) section
+# FAST:      _objc_msgSend$instance:
+# FAST-NEXT: adrp    x1,
+# FAST-NEXT: ldr     x1, {{.*}} ; Objc selector ref: instance
+# FAST-NEXT: adrp    x16,
+# FAST-NEXT: ldr     x16,
+# FAST-NEXT: br      x16
+# FAST-NEXT: brk     #0x1
+# FAST-NEXT: brk     #0x1
+# FAST-NEXT: brk     #0x1
+# FAST-NEXT: _objc_msgSendClass$external$_OBJC_CLASS_$_ExternalClass:
+# FAST-NEXT: adrp    x0,
+# FAST-NEXT: ldr     x0, {{.*}} ; literal pool symbol address: _OBJC_CLASS_$_ExternalClass
+# FAST-NEXT: adrp    x1,
+# FAST-NEXT: ldr     x1, {{.*}} ; Objc selector ref: external
+# FAST-NEXT: adrp    x16,
+# FAST-NEXT: ldr     x16,
+# FAST-NEXT: br      x16
+# FAST-NEXT: brk     #0x1
+# FAST-NEXT: _objc_msgSendClass$local$_OBJC_CLASS_$_LocalClass:
+# FAST-NEXT: adrp    x0,
+# FAST-NEXT: add     x0, x0,
+# FAST-NEXT: adrp    x1,
+# FAST-NEXT: ldr     x1, {{.*}} ; Objc selector ref: local
+# FAST-NEXT: adrp    x16,
+# FAST-NEXT: ldr     x16,
+# FAST-NEXT: br      x16
+# FAST-NEXT: brk     #0x1
+
+# SMALL:      Contents of (__TEXT,__objc_stubs) section
+# SMALL:      _objc_msgSend$instance:
+# SMALL-NEXT: adrp    x1,
+# SMALL-NEXT: ldr     x1, {{.*}} ; Objc selector ref: instance
+# SMALL-NEXT: b {{.*}}
+# SMALL-NEXT: _objc_msgSendClass$external$_OBJC_CLASS_$_ExternalClass:
+# SMALL-NEXT: adrp    x0,
+# SMALL-NEXT: ldr     x0, {{.*}} ; literal pool symbol address: _OBJC_CLASS_$_ExternalClass
+# SMALL-NEXT: adrp    x1,
+# SMALL-NEXT: ldr     x1, {{.*}} ; Objc selector ref: external
+# SMALL-NEXT: b {{.*}}
+# SMALL-NEXT: _objc_msgSendClass$local$_OBJC_CLASS_$_LocalClass:
+# SMALL-NEXT: adrp    x0,
+# SMALL-NEXT: add     x0, x0,
+# SMALL-NEXT: adrp    x1,
+# SMALL-NEXT: ldr     x1, {{.*}} ; Objc selector ref: local
+# SMALL-NEXT: b {{.*}}
+
+# DYNAMIC:      Contents of (__TEXT,__objc_stubs) section
+# DYNAMIC-NEXT: _objc_msgSendClass$dynamic$_OBJC_CLASS_$_DynamicClass:
+# DYNAMIC-NEXT: adrp    x0,
+# DYNAMIC-NEXT: ldr     x0, {{.*}} ; literal pool symbol address: _OBJC_CLASS_$_DynamicClass
+# DYNAMIC-NEXT: adrp    x1,
+# DYNAMIC-NEXT: ldr     x1, {{.*}} ; Objc selector ref: dynamic
+# DYNAMIC-NEXT: adrp    x16,
+# DYNAMIC-NEXT: ldr     x16, {{.*}} ; literal pool symbol address: _objc_msgSend
+# DYNAMIC-NEXT: br      x16
+# DYNAMIC-NEXT: brk     #0x1
+
+# ARCHIVE:      Contents of (__TEXT,__objc_stubs) section
+# ARCHIVE-NEXT: _objc_msgSendClass$archive$_OBJC_CLASS_$_ArchiveClass:
+# ARCHIVE-NEXT: adrp    x0,
+# ARCHIVE-NEXT: add     x0, x0,
+# ARCHIVE-NEXT: adrp    x1,
+# ARCHIVE-NEXT: ldr     x1, {{.*}} ; Objc selector ref: archive
+# ARCHIVE-NEXT: adrp    x16,
+# ARCHIVE-NEXT: ldr     x16,
+# ARCHIVE-NEXT: br      x16
+# ARCHIVE-NEXT: brk     #0x1
+#
+# ARCHIVE-SYMS: _OBJC_CLASS_$_ArchiveClass
+
+# AUTOLINK-A:      Contents of (__TEXT,__objc_stubs) section
+# AUTOLINK-A-NEXT: _objc_msgSendClass$auto$_OBJC_CLASS_$_AutoClass:
+# AUTOLINK-A-NEXT: adrp    x0,
+# AUTOLINK-A-NEXT: add     x0, x0,
+# AUTOLINK-A-NEXT: adrp    x1,
+# AUTOLINK-A-NEXT: ldr     x1, {{.*}} ; Objc selector ref: auto
+# AUTOLINK-A-NEXT: adrp    x16,
+# AUTOLINK-A-NEXT: ldr     x16,
+# AUTOLINK-A-NEXT: br      x16
+# AUTOLINK-A-NEXT: brk     #0x1
+#
+# AUTOLINK-B:      Contents of (__TEXT,__objc_stubs) section
+# AUTOLINK-B-NEXT: _objc_msgSendClass$late$_OBJC_CLASS_$_LateClass:
+# AUTOLINK-B-NEXT: adrp    x0,
+# AUTOLINK-B-NEXT: add     x0, x0,
+# AUTOLINK-B-NEXT: adrp    x1,
+# AUTOLINK-B-NEXT: ldr     x1, {{.*}} ; Objc selector ref: late
+# AUTOLINK-B-NEXT: adrp    x16,
+# AUTOLINK-B-NEXT: ldr     x16,
+# AUTOLINK-B-NEXT: br      x16
+# AUTOLINK-B-NEXT: brk     #0x1
+#
+# AUTOLINK-B-SYMS: _OBJC_CLASS_$_LateClass
+
+# MISSING: error: undefined symbol: _OBJC_CLASS_$_MissingClass
+# MISSING-NEXT: >>> referenced by objc class stub
+
+# MALFORMED: error: malformed objc class stub symbol _objc_msgSendClass$malformed; expected _objc_msgSendClass$<selector>$_OBJC_CLASS_$_<class>
+# MALFORMED-NOT: Objc selector ref:
+# MALFORMED-NOT: undefined symbol: _objc_msgSendClass$malformed
+
+#--- main.s
+# Main fast/small case: one regular selector stub plus local and dylib class stubs.
+.section __TEXT,__objc_methname,cstring_literals
+Linstance:
+  .asciz "instance"
+Llocal:
+  .asciz "local"
+Lexternal:
+  .asciz "external"
+
+.section __DATA,__objc_selrefs,literal_pointers,no_dead_strip
+.p2align 3
+  .quad Linstance
+  .quad Llocal
+  .quad Lexternal
+
+.text
+.globl _objc_msgSend
+_objc_msgSend:
+  ret
+
+.globl _main
+_main:
+  bl _objc_msgSend$instance
+  bl _objc_msgSendClass$local$_OBJC_CLASS_$_LocalClass
+  bl _objc_msgSendClass$external$_OBJC_CLASS_$_ExternalClass
+  ret
+
+.data
+.globl _OBJC_CLASS_$_LocalClass
+_OBJC_CLASS_$_LocalClass:
+  .quad 0
+
+.subsections_via_symbols
+
+#--- external.s
+# Provides the dylib-defined class used by main.s.
+.data
+.globl _OBJC_CLASS_$_ExternalClass
+_OBJC_CLASS_$_ExternalClass:
+  .quad 0
+
+#--- dynamic.s
+# Uses a class stub whose class symbol is resolved dynamically.
+.section __TEXT,__objc_methname,cstring_literals
+Ldynamic:
+  .asciz "dynamic"
+
+.section __DATA,__objc_selrefs,literal_pointers,no_dead_strip
+.p2align 3
+  .quad Ldynamic
+
+.text
+.globl _main
+_main:
+  bl _objc_msgSendClass$dynamic$_OBJC_CLASS_$_DynamicClass
+  ret
+
+#--- archive-main.s
+# References a class stub whose class definition must be pulled from an archive.
+.text
+.globl _main
+_main:
+  bl _objc_msgSendClass$archive$_OBJC_CLASS_$_ArchiveClass
+  ret
+
+#--- archive-class.s
+# Archive member defining the class used by archive-main.s.
+.data
+.globl _OBJC_CLASS_$_ArchiveClass
+_OBJC_CLASS_$_ArchiveClass:
+  .quad 0
+
+#--- autolink-main-a.s
+# Autolinks an archive member that contains both the stub user and class.
+.linker_option "-lautolinka"
+.text
+.globl _main
+_main:
+  bl _dep_a
+  ret
+
+#--- autolink-dep-a.s
+# Autolinked member containing the class-stub reference and class definition.
+.text
+.globl _dep_a
+_dep_a:
+  bl _objc_msgSendClass$auto$_OBJC_CLASS_$_AutoClass
+  ret
+
+.data
+.globl _OBJC_CLASS_$_AutoClass
+_OBJC_CLASS_$_AutoClass:
+  .quad 0
+
+#--- autolink-main-b.s
+# Autolinks an archive member that references a class defined in this object.
+.linker_option "-lautolinkb"
+.text
+.globl _main
+_main:
+  bl _dep_b
+  ret
+
+.data
+.globl _OBJC_CLASS_$_LateClass
+_OBJC_CLASS_$_LateClass:
+  .quad 0
+
+#--- autolink-dep-b.s
+# Autolinked member that introduces a late class-stub reference.
+.text
+.globl _dep_b
+_dep_b:
+  bl _objc_msgSendClass$late$_OBJC_CLASS_$_LateClass
+  ret
+
+#--- missing.s
+# References a live class stub whose class symbol is unresolved.
+.section __TEXT,__objc_methname,cstring_literals
+Lmissing:
+  .asciz "missing"
+
+.section __DATA,__objc_selrefs,literal_pointers,no_dead_strip
+.p2align 3
+  .quad Lmissing
+
+.text
+.globl _objc_msgSend
+_objc_msgSend:
+  ret
+
+.globl _main
+_main:
+  bl _objc_msgSendClass$missing$_OBJC_CLASS_$_MissingClass
+  ret
+
+#--- malformed.s
+# References a class stub symbol without the required class-symbol suffix.
+.text
+.globl _main
+_main:
+  bl _objc_msgSendClass$malformed
+  ret
diff --git a/lld/test/MachO/objc-class-stubs-unsupported.s b/lld/test/MachO/objc-class-stubs-unsupported.s
new file mode 100644
index 0000000000000..6d7e5a1e64777
--- /dev/null
+++ b/lld/test/MachO/objc-class-stubs-unsupported.s
@@ -0,0 +1,66 @@
+# REQUIRES: aarch64, x86
+
+# Tests that ObjC class stubs are rejected on architectures without an encoding.
+
+# RUN: rm -rf %t && split-file %s %t
+
+# Check x86_64 rejection.
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/x86_64.s \
+# RUN:   -o %t/x86_64.o
+# RUN: not %lld -arch x86_64 -lSystem -o /dev/null %t/x86_64.o \
+# RUN:   -objc_stubs_fast 2>&1 | FileCheck %s --check-prefix=X86_64
+
+# Check arm64e rejection.
+# RUN: llvm-mc -filetype=obj -triple=arm64e-apple-darwin %t/arm64.s \
+# RUN:   -o %t/arm64e.o
+# RUN: not %lld -arch arm64e -lSystem -o /dev/null %t/arm64e.o \
+# RUN:   -objc_stubs_fast 2>&1 | FileCheck %s --check-prefix=ARM64E
+
+# Check arm64_32 rejection.
+# RUN: llvm-mc -filetype=obj -triple=arm64_32-apple-watchos %t/arm64_32.s \
+# RUN:   -o %t/arm64_32.o
+# RUN: not %lld-watchos -arch arm64_32 -lSystem -o /dev/null %t/arm64_32.o \
+# RUN:   -objc_stubs_fast 2>&1 | FileCheck %s --check-prefix=ARM64_32
+
+# X86_64: error: objc class stubs are not supported for x86_64
+# ARM64E: error: objc class stubs are not supported for arm64e
+# ARM64_32: error: objc class stubs are not supported for arm64_32
+
+#--- x86_64.s
+# x86_64 input should reject class-stub symbols.
+.text
+.globl _main
+_main:
+  callq _objc_msgSendClass$foo$_OBJC_CLASS_$_Foo
+  ret
+
+.data
+.globl _OBJC_CLASS_$_Foo
+_OBJC_CLASS_$_Foo:
+  .quad 0
+
+#--- arm64.s
+# arm64e input should reject class-stub symbols until supported.
+.text
+.globl _main
+_main:
+  bl _objc_msgSendClass$foo$_OBJC_CLASS_$_Foo
+  ret
+
+.data
+.globl _OBJC_CLASS_$_Foo
+_OBJC_CLASS_$_Foo:
+  .quad 0
+
+#--- arm64_32.s
+# arm64_32 input should reject class-stub symbols.
+.text
+.globl _main
+_main:
+  bl _objc_msgSendClass$foo$_OBJC_CLASS_$_Foo
+  ret
+
+.data
+.globl _OBJC_CLASS_$_Foo
+_OBJC_CLASS_$_Foo:
+  .long 0



More information about the llvm-branch-commits mailing list