https://github.com/VisualEhrmanntraut updated 
https://github.com/llvm/llvm-project/pull/204805

>From 528a1425cb26cebc400a6deb32604b04da392805 Mon Sep 17 00:00:00 2001
From: Visual <[email protected]>
Date: Fri, 19 Jun 2026 15:25:37 +0300
Subject: [PATCH 1/3] Somewhat finished Apple Kext support

---
 clang/lib/Driver/ToolChains/Darwin.cpp        | 23 +++--
 .../InstallAPI/DiagnosticBuilderWrappers.cpp  |  3 +
 lld/MachO/Driver.cpp                          |  9 +-
 lld/MachO/InputSection.cpp                    |  8 ++
 lld/MachO/InputSection.h                      |  2 +
 lld/MachO/Options.td                          |  7 +-
 lld/MachO/SyntheticSections.cpp               | 98 +++++++++++++++----
 lld/MachO/SyntheticSections.h                 | 45 +++++++++
 lld/MachO/Writer.cpp                          | 48 +++++++--
 llvm/include/llvm/TextAPI/FileTypes.h         | 13 ++-
 llvm/lib/CodeGen/TargetPassConfig.cpp         | 10 +-
 llvm/lib/TextAPI/BinaryReader/DylibReader.cpp |  3 +
 12 files changed, 219 insertions(+), 50 deletions(-)

diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp 
b/clang/lib/Driver/ToolChains/Darwin.cpp
index 59744d1cb3e8c..ee970b3d3aa89 100644
--- a/clang/lib/Driver/ToolChains/Darwin.cpp
+++ b/clang/lib/Driver/ToolChains/Darwin.cpp
@@ -312,10 +312,6 @@ void darwin::Linker::AddLinkArgs(Compilation &C, const 
ArgList &Args,
     // FIXME: Why do this only on this path?
     Args.AddLastArg(CmdArgs, options::OPT_force__cpusubtype__ALL);
 
-    Args.AddLastArg(CmdArgs, options::OPT_bundle);
-    Args.AddAllArgs(CmdArgs, options::OPT_bundle__loader);
-    Args.AddAllArgs(CmdArgs, options::OPT_client__name);
-
     Arg *A;
     if ((A = Args.getLastArg(options::OPT_compatibility__version)) ||
         (A = Args.getLastArg(options::OPT_current__version)) ||
@@ -323,14 +319,25 @@ void darwin::Linker::AddLinkArgs(Compilation &C, const 
ArgList &Args,
       D.Diag(diag::err_drv_argument_only_allowed_with) << A->getAsString(Args)
                                                        << "-dynamiclib";
 
-    Args.AddLastArg(CmdArgs, options::OPT_force__flat__namespace);
+    if ((A = Args.getLastArg(options::OPT_fapple_kext))) {
+      CmdArgs.push_back("-kext");
+      CmdArgs.push_back("-undefined");
+      CmdArgs.push_back("dynamic_lookup");
+    } else {
+      Args.AddLastArg(CmdArgs, options::OPT_bundle);
+      Args.AddAllArgs(CmdArgs, options::OPT_bundle__loader);
+      Args.AddLastArg(CmdArgs, options::OPT_force__flat__namespace);
+      Args.AddLastArg(CmdArgs, options::OPT_private__bundle);
+    }
+
+    Args.AddAllArgs(CmdArgs, options::OPT_client__name);
     Args.AddLastArg(CmdArgs, options::OPT_keep__private__externs);
-    Args.AddLastArg(CmdArgs, options::OPT_private__bundle);
   } else {
     CmdArgs.push_back("-dylib");
 
     Arg *A;
-    if ((A = Args.getLastArg(options::OPT_bundle)) ||
+    if ((A = Args.getLastArg(options::OPT_fapple_kext)) ||
+        (A = Args.getLastArg(options::OPT_bundle)) ||
         (A = Args.getLastArg(options::OPT_bundle__loader)) ||
         (A = Args.getLastArg(options::OPT_client__name)) ||
         (A = Args.getLastArg(options::OPT_force__flat__namespace)) ||
@@ -4023,6 +4030,8 @@ void Darwin::addStartObjectFileArgs(const ArgList &Args,
   // Derived from startfile spec.
   if (Args.hasArg(options::OPT_dynamiclib))
     addDynamicLibLinkArgs(*this, Args, CmdArgs);
+  else if (Args.hasArg(options::OPT_fapple_kext))
+    CmdArgs.push_back("-kext"); // TODO ?
   else if (Args.hasArg(options::OPT_bundle))
     addBundleLinkArgs(*this, Args, CmdArgs);
   else if (Args.hasArg(options::OPT_pg) && SupportsProfiling())
diff --git a/clang/lib/InstallAPI/DiagnosticBuilderWrappers.cpp 
b/clang/lib/InstallAPI/DiagnosticBuilderWrappers.cpp
index 37b428216c91e..4e093392f5c34 100644
--- a/clang/lib/InstallAPI/DiagnosticBuilderWrappers.cpp
+++ b/clang/lib/InstallAPI/DiagnosticBuilderWrappers.cpp
@@ -57,6 +57,9 @@ const DiagnosticBuilder &operator<<(const DiagnosticBuilder 
&DB,
   case FileType::MachO_Bundle:
     DB.AddString("mach-o bundle");
     return DB;
+  case FileType::MachO_KextBundle:
+    DB.AddString("mach-o kext bundle");
+    return DB;
   case FileType::MachO_DynamicLibrary:
     DB.AddString("mach-o dynamic library");
     return DB;
diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp
index 2864c6d28fa49..9b821deba2922 100644
--- a/lld/MachO/Driver.cpp
+++ b/lld/MachO/Driver.cpp
@@ -72,11 +72,14 @@ std::unique_ptr<DependencyTracker> macho::depTracker;
 
 static HeaderFileType getOutputType(const InputArgList &args) {
   // TODO: -r, -dylinker, -preload...
-  Arg *outputArg = args.getLastArg(OPT_bundle, OPT_dylib, OPT_execute);
+  Arg *outputArg =
+      args.getLastArg(OPT_kext, OPT_bundle, OPT_dylib, OPT_execute);
   if (outputArg == nullptr)
     return MH_EXECUTE;
 
   switch (outputArg->getOption().getID()) {
+  case OPT_kext:
+    return MH_KEXT_BUNDLE;
   case OPT_bundle:
     return MH_BUNDLE;
   case OPT_dylib:
@@ -1269,6 +1272,7 @@ static bool dataConstDefault(const InputArgList &args) {
 
   switch (config->outputType) {
   case MH_EXECUTE:
+  case MH_KEXT_BUNDLE:
     return !(args.hasArg(OPT_no_pie) && supportsNoPie());
   case MH_BUNDLE:
     // FIXME: return false when -final_name ...
@@ -1888,7 +1892,8 @@ bool link(ArrayRef<const char *> argsArr, 
llvm::raw_ostream &stdoutOS,
     pie = true;
   }
 
-  config->isPic = config->outputType == MH_DYLIB ||
+  config->isPic = config->outputType == MH_KEXT_BUNDLE ||
+                  config->outputType == MH_DYLIB ||
                   config->outputType == MH_BUNDLE ||
                   (config->outputType == MH_EXECUTE && pie);
 
diff --git a/lld/MachO/InputSection.cpp b/lld/MachO/InputSection.cpp
index 4c4f644889d5f..2aa2836c4f3a4 100644
--- a/lld/MachO/InputSection.cpp
+++ b/lld/MachO/InputSection.cpp
@@ -247,6 +247,14 @@ void ConcatInputSection::writeTo(uint8_t *buf) {
       if (target->hasAttr(r.type, RelocAttrBits::LOAD) &&
           !referentSym->isInGot())
         target->relaxGotLoad(loc, r.type);
+      if (config->outputType == MH_KEXT_BUNDLE && !needsFixup &&
+          needsBinding(referentSym)) {
+        if (target->hasAttr(r.type, RelocAttrBits::BRANCH)) {
+          continue;
+        }
+        if (!referentSym->isInGot())
+          continue;
+      }
       // For dtrace symbols, do not handle them as normal undefined symbols
       if (referentSym->getName().starts_with("___dtrace_")) {
         // Change dtrace call site to pre-defined instructions
diff --git a/lld/MachO/InputSection.h b/lld/MachO/InputSection.h
index 8fcd16a1de35f..27b96a19b6d96 100644
--- a/lld/MachO/InputSection.h
+++ b/lld/MachO/InputSection.h
@@ -381,6 +381,8 @@ constexpr const char unwindInfo[] = "__unwind_info";
 constexpr const char weakBinding[] = "__weak_binding";
 constexpr const char zeroFill[] = "__zerofill";
 constexpr const char addrSig[] = "__llvm_addrsig";
+constexpr const char extRelocs[] = "__ext_relocs";
+constexpr const char localRelocs[] = "__local_relocs";
 
 } // namespace section_names
 
diff --git a/lld/MachO/Options.td b/lld/MachO/Options.td
index b7686d66a258e..99ad8436f0d44 100644
--- a/lld/MachO/Options.td
+++ b/lld/MachO/Options.td
@@ -238,6 +238,9 @@ def dylib : Flag<["-"], "dylib">,
 def bundle : Flag<["-"], "bundle">,
     HelpText<"Produce a bundle">,
     Group<grp_kind>;
+def kext : Flag<["-"], "kext">,
+    HelpText<"Produce a kext bundle">,
+    Group<grp_kind>;
 def r : Flag<["-"], "r">,
     HelpText<"Merge multiple object files into one, retaining relocations">,
     Flags<[HelpHidden]>,
@@ -1426,10 +1429,6 @@ def no_keep_dwarf_unwind : Flag<["-"], 
"no_keep_dwarf_unwind">,
     HelpText<"This option is undocumented in ld64">,
     Flags<[HelpHidden]>,
     Group<grp_undocumented>;
-def kext : Flag<["-"], "kext">,
-    HelpText<"This option is undocumented in ld64">,
-    Flags<[HelpHidden]>,
-    Group<grp_undocumented>;
 def kext_objects_dir : Flag<["-"], "kext_objects_dir">,
     HelpText<"This option is undocumented in ld64">,
     Flags<[HelpHidden]>,
diff --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp
index ba06a95bb753c..29fec8b1ced7f 100644
--- a/lld/MachO/SyntheticSections.cpp
+++ b/lld/MachO/SyntheticSections.cpp
@@ -106,12 +106,14 @@ static uint32_t cpuSubtype() {
 
 static bool hasWeakBinding() {
   return config->emitChainedFixups ? in.chainedFixups->hasWeakBinding()
-                                   : in.weakBinding->hasEntry();
+                                   : config->outputType != MH_KEXT_BUNDLE &&
+                                         in.weakBinding->hasEntry();
 }
 
 static bool hasNonWeakDefinition() {
   return config->emitChainedFixups ? in.chainedFixups->hasNonWeakDefinition()
-                                   : in.weakBinding->hasNonWeakDefinition();
+                                   : config->outputType != MH_KEXT_BUNDLE &&
+                                         
in.weakBinding->hasNonWeakDefinition();
 }
 
 void MachHeaderSection::writeTo(uint8_t *buf) const {
@@ -317,6 +319,18 @@ void macho::addNonLazyBindingEntries(const Symbol *sym,
     return;
   }
 
+  if (config->outputType == MH_KEXT_BUNDLE) {
+    if (needsBinding(sym))
+      in.extRelocs->addEntry(sym, isec, offset, target->unsignedRelocType,
+                             /*pcrel=*/false, target->p2WordSize);
+    else if (isa<Defined>(sym))
+      in.localRelocs->addEntry(sym, isec, offset, target->unsignedRelocType,
+                               /*pcrel=*/false, target->p2WordSize);
+    else
+      llvm_unreachable("cannot bind to an undefined symbol");
+    return;
+  }
+
   if (const auto *dysym = dyn_cast<DylibSymbol>(sym)) {
     in.binding->addEntry(dysym, isec, offset, addend);
     if (dysym->isWeakDef())
@@ -758,7 +772,7 @@ void StubsSection::addEntry(Symbol *sym) {
   if (inserted) {
     sym->stubsIndex = entries.size() - 1;
 
-    if (config->emitChainedFixups)
+    if (config->emitChainedFixups || config->outputType == MH_KEXT_BUNDLE)
       in.got->addEntry(sym);
     else
       addBindingsForStub(sym);
@@ -816,6 +830,40 @@ void StubHelperSection::setUp() {
   dyldPrivate->used = true;
 }
 
+RelocSection::RelocSection(const char *name)
+    : LinkEditSection(segment_names::linkEdit, name) {}
+
+void RelocSection::writeTo(uint8_t *buf) const {
+  for (const Entry &e : entries) {
+    write32le(buf, e.isec->getVA(e.offset));
+
+    const bool ext = this->isExternal();
+    uint32_t symOrSectNum;
+    if (ext)
+      symOrSectNum = e.sym->symtabIndex;
+    else {
+      const auto *def = dyn_cast_or_null<Defined>(e.sym);
+      const InputSection *targetIsec = def ? def->isec() : e.isec;
+      symOrSectNum = targetIsec->parent->index;
+    }
+
+    write32le(buf + sizeof(uint32_t),
+              (symOrSectNum & 0x00ffffffu) |
+                  (static_cast<uint32_t>(e.pcrel) << 24) |
+                  (static_cast<uint32_t>(e.length) << 25) |
+                  (static_cast<uint32_t>(ext) << 27) |
+                  (static_cast<uint32_t>(e.type) << 28));
+
+    buf += sizeof(uint32_t) * 2;
+  }
+}
+
+ExternalRelocSection::ExternalRelocSection()
+    : RelocSection(section_names::extRelocs) {}
+
+LocalRelocSection::LocalRelocSection()
+    : RelocSection(section_names::localRelocs) {}
+
 llvm::DenseMap<llvm::CachedHashStringRef, ConcatInputSection *>
     ObjCSelRefsHelper::methnameToSelref;
 void ObjCSelRefsHelper::initialize() {
@@ -1479,28 +1527,31 @@ IndirectSymtabSection::IndirectSymtabSection()
                       section_names::indirectSymbolTable) {}
 
 uint32_t IndirectSymtabSection::getNumSymbols() const {
-  uint32_t size = in.got->getEntries().size() +
-                  in.tlvPointers->getEntries().size() +
-                  in.stubs->getEntries().size();
-  if (!config->emitChainedFixups)
-    size += in.stubs->getEntries().size();
+  uint32_t size = in.got->getEntries().size();
+  if (config->outputType != MH_KEXT_BUNDLE)
+    size += in.tlvPointers->getEntries().size() +
+            in.stubs->getEntries().size() * (config->emitChainedFixups ? 1 : 
2);
   return size;
 }
 
 bool IndirectSymtabSection::isNeeded() const {
-  return in.got->isNeeded() || in.tlvPointers->isNeeded() ||
-         in.stubs->isNeeded();
+  return in.got->isNeeded() || (in.tlvPointers && in.tlvPointers->isNeeded()) 
||
+         (in.stubs && in.stubs->isNeeded());
 }
 
 void IndirectSymtabSection::finalizeContents() {
   uint32_t off = 0;
   in.got->reserved1 = off;
   off += in.got->getEntries().size();
-  in.tlvPointers->reserved1 = off;
-  off += in.tlvPointers->getEntries().size();
-  in.stubs->reserved1 = off;
-  if (in.lazyPointers) {
+  if (in.tlvPointers) {
+    in.tlvPointers->reserved1 = off;
+    off += in.tlvPointers->getEntries().size();
+  }
+  if (in.stubs) {
+    in.stubs->reserved1 = off;
     off += in.stubs->getEntries().size();
+  }
+  if (in.lazyPointers) {
     in.lazyPointers->reserved1 = off;
   }
 }
@@ -1517,13 +1568,17 @@ void IndirectSymtabSection::writeTo(uint8_t *buf) const 
{
     write32le(buf + off * sizeof(uint32_t), indirectValue(sym));
     ++off;
   }
-  for (const Symbol *sym : in.tlvPointers->getEntries()) {
-    write32le(buf + off * sizeof(uint32_t), indirectValue(sym));
-    ++off;
+  if (in.tlvPointers) {
+    for (const Symbol *sym : in.tlvPointers->getEntries()) {
+      write32le(buf + off * sizeof(uint32_t), indirectValue(sym));
+      ++off;
+    }
   }
-  for (const Symbol *sym : in.stubs->getEntries()) {
-    write32le(buf + off * sizeof(uint32_t), indirectValue(sym));
-    ++off;
+  if (in.stubs) {
+    for (const Symbol *sym : in.stubs->getEntries()) {
+      write32le(buf + off * sizeof(uint32_t), indirectValue(sym));
+      ++off;
+    }
   }
 
   if (in.lazyPointers) {
@@ -2321,6 +2376,9 @@ void macho::createSyntheticSymbols() {
     // The following symbols are N_SECT symbols, even though the header is not
     // part of any section and that they are private to the bundle/dylib/object
     // they are part of.
+  case MH_KEXT_BUNDLE:
+    addHeaderSymbol("__mh_kext_bundle_header");
+    break;
   case MH_BUNDLE:
     addHeaderSymbol("__mh_bundle_header");
     break;
diff --git a/lld/MachO/SyntheticSections.h b/lld/MachO/SyntheticSections.h
index e649d1275f821..504fa14e9d8b3 100644
--- a/lld/MachO/SyntheticSections.h
+++ b/lld/MachO/SyntheticSections.h
@@ -300,6 +300,49 @@ class StubsSection final : public SyntheticSection {
   llvm::SetVector<Symbol *> entries;
 };
 
+class RelocSection : public LinkEditSection {
+public:
+  RelocSection(const char *name);
+  bool isNeeded() const override { return !entries.empty(); }
+  uint64_t getRawSize() const override {
+    return entries.size() * (sizeof(uint32_t) * 2);
+  }
+  void addEntry(const Symbol *sym, const InputSection *isec, uint32_t offset,
+                uint8_t type, bool pcrel, uint8_t length) {
+    entries.emplace_back(sym, isec, offset, type, pcrel, length);
+  }
+  void writeTo(uint8_t *buf) const override;
+
+  virtual bool isExternal() const = 0;
+
+  struct Entry {
+    const Symbol *sym;
+    const InputSection *isec;
+    uint32_t offset;
+    uint8_t type;
+    bool pcrel;
+    uint8_t length;
+
+    Entry(const Symbol *sym, const InputSection *isec, uint32_t offset,
+          uint8_t type, bool pcrel, uint8_t length)
+        : sym(sym), isec(isec), offset(offset), type(type), pcrel(pcrel),
+          length(length) {}
+  };
+  std::vector<Entry> entries;
+};
+
+class ExternalRelocSection final : public RelocSection {
+public:
+  ExternalRelocSection();
+  bool isExternal() const override { return true; }
+};
+
+class LocalRelocSection final : public RelocSection {
+public:
+  LocalRelocSection();
+  bool isExternal() const override { return false; }
+};
+
 class StubHelperSection final : public SyntheticSection {
 public:
   StubHelperSection();
@@ -850,6 +893,8 @@ struct InStruct {
   InitOffsetsSection *initOffsets = nullptr;
   ObjCMethListSection *objcMethList = nullptr;
   ChainedFixupsSection *chainedFixups = nullptr;
+  ExternalRelocSection *extRelocs = nullptr;
+  LocalRelocSection *localRelocs = nullptr;
 
   CStringSection *getOrCreateCStringSection(StringRef name,
                                             bool forceDedupStrings = false) {
diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp
index 89b6d467d0d44..936dea8658de6 100644
--- a/lld/MachO/Writer.cpp
+++ b/lld/MachO/Writer.cpp
@@ -212,6 +212,16 @@ class LCDysymtab final : public LoadCommand {
 
     c->indirectsymoff = indirectSymtabSection->fileOff;
     c->nindirectsyms = indirectSymtabSection->getNumSymbols();
+
+    // For kext bundles
+    if (in.extRelocs && in.extRelocs->isNeeded()) {
+      c->extreloff = in.extRelocs->fileOff;
+      c->nextrel = in.extRelocs->entries.size();
+    }
+    if (in.localRelocs && in.localRelocs->isNeeded()) {
+      c->locreloff = in.localRelocs->fileOff;
+      c->nlocrel = in.localRelocs->entries.size();
+    }
   }
 
   SymtabSection *symtabSection;
@@ -678,12 +688,23 @@ static void prepareSymbolRelocation(Symbol *sym, const 
InputSection *isec,
   const RelocAttrs &relocAttrs = target->getRelocAttrs(r.type);
 
   if (relocAttrs.hasAttr(RelocAttrBits::BRANCH)) {
-    if (needsBinding(sym))
-      in.stubs->addEntry(sym);
+    if (needsBinding(sym)) {
+      if (config->outputType == MH_KEXT_BUNDLE) {
+        in.extRelocs->addEntry(sym, isec, r.offset, r.type, r.pcrel, r.length);
+      } else {
+        in.stubs->addEntry(sym);
+      }
+    }
   } else if (relocAttrs.hasAttr(RelocAttrBits::GOT)) {
     if (relocAttrs.hasAttr(RelocAttrBits::POINTER) || needsBinding(sym))
       in.got->addEntry(sym);
   } else if (relocAttrs.hasAttr(RelocAttrBits::TLV)) {
+    if (config->outputType == MH_KEXT_BUNDLE) {
+      fatal(isec->getLocation(r.offset) +
+            ": TLV reference to external symbol " + sym->getName() +
+            " is not supported in kext bundles");
+      return;
+    }
     if (needsBinding(sym))
       in.tlvPointers->addEntry(sym);
   } else if (relocAttrs.hasAttr(RelocAttrBits::UNSIGNED)) {
@@ -735,6 +756,9 @@ void Writer::scanRelocations() {
         if (!r.pcrel) {
           if (config->emitChainedFixups)
             in.chainedFixups->addRebase(isec, r.offset);
+          else if (config->outputType == MH_KEXT_BUNDLE)
+            in.localRelocs->addEntry(sym, isec, r.offset, r.type, false,
+                                     r.length);
           else
             in.rebase->addEntry(isec, r.offset);
         }
@@ -824,8 +848,10 @@ template <class LP> void Writer::createLoadCommands() {
 
   if (config->emitChainedFixups) {
     in.header->addLoadCommand(make<LCChainedFixups>(in.chainedFixups));
-    in.header->addLoadCommand(make<LCExportsTrie>(in.exports));
-  } else {
+    if (in.exports->isNeeded()) {
+      in.header->addLoadCommand(make<LCExportsTrie>(in.exports));
+    }
+  } else if (config->outputType != MH_KEXT_BUNDLE) {
     in.header->addLoadCommand(make<LCDyldInfo>(
         in.rebase, in.binding, in.weakBinding, in.lazyBinding, in.exports));
   }
@@ -851,6 +877,7 @@ template <class LP> void Writer::createLoadCommands() {
       in.header->addLoadCommand(make<LCSubClient>(client));
     break;
   case MH_BUNDLE:
+  case MH_KEXT_BUNDLE:
     break;
   default:
     llvm_unreachable("unhandled output file type");
@@ -1042,6 +1069,7 @@ template <class LP> void Writer::createOutputSections() {
     break;
   case MH_DYLIB:
   case MH_BUNDLE:
+  case MH_KEXT_BUNDLE:
     break;
   default:
     llvm_unreachable("unhandled output file type");
@@ -1147,10 +1175,11 @@ void Writer::finalizeAddresses() {
 void Writer::finalizeLinkEditSegment() {
   TimeTraceScope timeScope("Finalize __LINKEDIT segment");
   // Fill __LINKEDIT contents.
-  std::array<LinkEditSection *, 10> linkEditSections{
+  std::array<LinkEditSection *, 12> linkEditSections{
       in.rebase,         in.binding,
       in.weakBinding,    in.lazyBinding,
       in.exports,        in.chainedFixups,
+      in.extRelocs,      in.localRelocs,
       symtabSection,     indirectSymtabSection,
       dataInCodeSection, functionStartsSection,
   };
@@ -1389,6 +1418,9 @@ void macho::createSyntheticSections() {
   in.wordLiteralSection = make<WordLiteralSection>();
   if (config->emitChainedFixups) {
     in.chainedFixups = make<ChainedFixupsSection>();
+  } else if (config->outputType == MH_KEXT_BUNDLE) {
+    in.extRelocs = make<ExternalRelocSection>();
+    in.localRelocs = make<LocalRelocSection>();
   } else {
     in.rebase = make<RebaseSection>();
     in.binding = make<BindingSection>();
@@ -1399,8 +1431,10 @@ void macho::createSyntheticSections() {
   }
   in.exports = make<ExportSection>();
   in.got = make<GotSection>();
-  in.tlvPointers = make<TlvPointerSection>();
-  in.stubs = make<StubsSection>();
+  if (config->outputType != MH_KEXT_BUNDLE) {
+    in.tlvPointers = make<TlvPointerSection>();
+    in.stubs = make<StubsSection>();
+  }
   in.objcStubs = make<ObjCStubsSection>();
   in.unwindInfo = makeUnwindInfoSection();
   in.objCImageInfo = make<ObjCImageInfoSection>();
diff --git a/llvm/include/llvm/TextAPI/FileTypes.h 
b/llvm/include/llvm/TextAPI/FileTypes.h
index 5876e9d5a5304..e0a41603fca20 100644
--- a/llvm/include/llvm/TextAPI/FileTypes.h
+++ b/llvm/include/llvm/TextAPI/FileTypes.h
@@ -25,20 +25,23 @@ enum FileType : unsigned {
   /// \brief MachO Bundle file.
   MachO_Bundle = 1U << 2,
 
+  /// \brief MachO Kext Bundle file.
+  MachO_KextBundle = 1U << 3,
+
   /// Text-based stub file (.tbd) version 1.0
-  TBD_V1 = 1U << 3,
+  TBD_V1 = 1U << 4,
 
   /// Text-based stub file (.tbd) version 2.0
-  TBD_V2 = 1U << 4,
+  TBD_V2 = 1U << 5,
 
   /// Text-based stub file (.tbd) version 3.0
-  TBD_V3 = 1U << 5,
+  TBD_V3 = 1U << 6,
 
   /// Text-based stub file (.tbd) version 4.0
-  TBD_V4 = 1U << 6,
+  TBD_V4 = 1U << 7,
 
   /// Text-based stub file (.tbd) version 5.0
-  TBD_V5 = 1U << 7,
+  TBD_V5 = 1U << 8,
 
   All = ~0U,
 
diff --git a/llvm/lib/CodeGen/TargetPassConfig.cpp 
b/llvm/lib/CodeGen/TargetPassConfig.cpp
index 4a76aba55b78b..13fdfc7de5f6d 100644
--- a/llvm/lib/CodeGen/TargetPassConfig.cpp
+++ b/llvm/lib/CodeGen/TargetPassConfig.cpp
@@ -872,11 +872,11 @@ void TargetPassConfig::addIRPasses() {
   addPass(&GCLoweringID);
   addPass(&ShadowStackGCLoweringID);
 
-  // For MachO, lower @llvm.global_dtors into @llvm.global_ctors with
-  // __cxa_atexit() calls to avoid emitting the deprecated __mod_term_func.
-  if (TM->getTargetTriple().isOSBinFormatMachO() &&
-      !DisableAtExitBasedGlobalDtorLowering)
-    addPass(createLowerGlobalDtorsLegacyPass());
+  // // For MachO, lower @llvm.global_dtors into @llvm.global_ctors with
+  // // __cxa_atexit() calls to avoid emitting the deprecated __mod_term_func.
+  // if (TM->getTargetTriple().isOSBinFormatMachO() &&
+  //     !DisableAtExitBasedGlobalDtorLowering)
+  //   addPass(createLowerGlobalDtorsLegacyPass());
 
   // Make sure that no unreachable blocks are instruction selected.
   addPass(createUnreachableBlockEliminationPass());
diff --git a/llvm/lib/TextAPI/BinaryReader/DylibReader.cpp 
b/llvm/lib/TextAPI/BinaryReader/DylibReader.cpp
index f55bc9c1a28c2..b072f6349e317 100644
--- a/llvm/lib/TextAPI/BinaryReader/DylibReader.cpp
+++ b/llvm/lib/TextAPI/BinaryReader/DylibReader.cpp
@@ -157,6 +157,9 @@ static Error readMachOHeader(MachOObjectFile *Obj, 
RecordsSlice &Slice) {
   case MachO::MH_BUNDLE:
     BA.File = FileType::MachO_Bundle;
     break;
+  case MachO::MH_KEXT_BUNDLE:
+    BA.File = FileType::MachO_KextBundle;
+    break;
   }
 
   if (H.flags & MachO::MH_TWOLEVEL)

>From f271660688448e60234a145adced07afd64b1b95 Mon Sep 17 00:00:00 2001
From: Visual <[email protected]>
Date: Tue, 23 Jun 2026 09:24:25 +0300
Subject: [PATCH 2/3] shouldEmitChainedFixups should always return false on
 x86_64 for kexts

---
 lld/MachO/Driver.cpp | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp
index 9b821deba2922..23f9b73a6079d 100644
--- a/lld/MachO/Driver.cpp
+++ b/lld/MachO/Driver.cpp
@@ -1310,6 +1310,14 @@ static bool shouldEmitChainedFixups(const InputArgList 
&args) {
     return false;
   }
 
+  if (args.hasArg(OPT_kext) &&
+      is_contained({AK_x86_64, AK_x86_64h}, config->arch())) {
+    if (requested)
+      error("-fixup_chains with -kext is only supported on arm64 targets");
+
+    return false;
+  }
+
   if (args.hasArg(OPT_preload)) {
     if (requested)
       error("-fixup_chains is incompatible with -preload");

>From 760107b67adfa888987177a9be39ba3cf9a032e7 Mon Sep 17 00:00:00 2001
From: Visual <[email protected]>
Date: Tue, 23 Jun 2026 10:11:22 +0300
Subject: [PATCH 3/3] Use finalizeContents for RelocSection

---
 lld/MachO/SyntheticSections.cpp | 39 +++++++++++++++++++++++----------
 lld/MachO/SyntheticSections.h   | 13 +++++------
 lld/MachO/Writer.cpp            |  8 +++++--
 3 files changed, 40 insertions(+), 20 deletions(-)

diff --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp
index 29fec8b1ced7f..c64b32081bee9 100644
--- a/lld/MachO/SyntheticSections.cpp
+++ b/lld/MachO/SyntheticSections.cpp
@@ -833,13 +833,27 @@ void StubHelperSection::setUp() {
 RelocSection::RelocSection(const char *name)
     : LinkEditSection(segment_names::linkEdit, name) {}
 
-void RelocSection::writeTo(uint8_t *buf) const {
+void RelocSection::addEntry(const Symbol *sym, const InputSection *isec,
+                            uint32_t offset, uint8_t type, bool pcrel,
+                            uint8_t length) {
+  assert(!this->isFinal && "RelocSection entry added after finalizeContents");
+  this->entries.emplace_back(sym, isec, offset, type, pcrel, length);
+}
+
+void RelocSection::finalizeContents() {
+  assert(!this->isFinal && "RelocSection finalized twice");
+  this->isFinal = true;
+
+  const bool isExternal = this->isExternal();
+
+  raw_svector_ostream os{contents};
   for (const Entry &e : entries) {
+    char buf[sizeof(uint32_t)];
     write32le(buf, e.isec->getVA(e.offset));
+    os.write(buf, sizeof(buf));
 
-    const bool ext = this->isExternal();
     uint32_t symOrSectNum;
-    if (ext)
+    if (isExternal)
       symOrSectNum = e.sym->symtabIndex;
     else {
       const auto *def = dyn_cast_or_null<Defined>(e.sym);
@@ -847,17 +861,20 @@ void RelocSection::writeTo(uint8_t *buf) const {
       symOrSectNum = targetIsec->parent->index;
     }
 
-    write32le(buf + sizeof(uint32_t),
-              (symOrSectNum & 0x00ffffffu) |
-                  (static_cast<uint32_t>(e.pcrel) << 24) |
-                  (static_cast<uint32_t>(e.length) << 25) |
-                  (static_cast<uint32_t>(ext) << 27) |
-                  (static_cast<uint32_t>(e.type) << 28));
-
-    buf += sizeof(uint32_t) * 2;
+    write32le(buf, (symOrSectNum & 0x00ffffffu) |
+                       (static_cast<uint32_t>(e.pcrel) << 24) |
+                       (static_cast<uint32_t>(e.length) << 25) |
+                       (static_cast<uint32_t>(isExternal) << 27) |
+                       (static_cast<uint32_t>(e.type) << 28));
+    os.write(buf, sizeof(buf));
   }
 }
 
+void RelocSection::writeTo(uint8_t *buf) const {
+  assert(this->isFinal && "RelocSection contents written before finalization");
+  memcpy(buf, contents.data(), contents.size());
+}
+
 ExternalRelocSection::ExternalRelocSection()
     : RelocSection(section_names::extRelocs) {}
 
diff --git a/lld/MachO/SyntheticSections.h b/lld/MachO/SyntheticSections.h
index 504fa14e9d8b3..1727fbd721020 100644
--- a/lld/MachO/SyntheticSections.h
+++ b/lld/MachO/SyntheticSections.h
@@ -303,14 +303,11 @@ class StubsSection final : public SyntheticSection {
 class RelocSection : public LinkEditSection {
 public:
   RelocSection(const char *name);
-  bool isNeeded() const override { return !entries.empty(); }
-  uint64_t getRawSize() const override {
-    return entries.size() * (sizeof(uint32_t) * 2);
-  }
   void addEntry(const Symbol *sym, const InputSection *isec, uint32_t offset,
-                uint8_t type, bool pcrel, uint8_t length) {
-    entries.emplace_back(sym, isec, offset, type, pcrel, length);
-  }
+                uint8_t type, bool pcrel, uint8_t length);
+  bool isNeeded() const override { return !entries.empty(); }
+  void finalizeContents() override;
+  uint64_t getRawSize() const override { return contents.size(); }
   void writeTo(uint8_t *buf) const override;
 
   virtual bool isExternal() const = 0;
@@ -328,7 +325,9 @@ class RelocSection : public LinkEditSection {
         : sym(sym), isec(isec), offset(offset), type(type), pcrel(pcrel),
           length(length) {}
   };
+  bool isFinal = false;
   std::vector<Entry> entries;
+  SmallVector<char, 128> contents;
 };
 
 class ExternalRelocSection final : public RelocSection {
diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp
index 936dea8658de6..4476f3a768416 100644
--- a/lld/MachO/Writer.cpp
+++ b/lld/MachO/Writer.cpp
@@ -1175,11 +1175,10 @@ void Writer::finalizeAddresses() {
 void Writer::finalizeLinkEditSegment() {
   TimeTraceScope timeScope("Finalize __LINKEDIT segment");
   // Fill __LINKEDIT contents.
-  std::array<LinkEditSection *, 12> linkEditSections{
+  std::array<LinkEditSection *, 10> linkEditSections{
       in.rebase,         in.binding,
       in.weakBinding,    in.lazyBinding,
       in.exports,        in.chainedFixups,
-      in.extRelocs,      in.localRelocs,
       symtabSection,     indirectSymtabSection,
       dataInCodeSection, functionStartsSection,
   };
@@ -1190,6 +1189,11 @@ void Writer::finalizeLinkEditSegment() {
                       osec->finalizeContents();
                   });
 
+  if (in.extRelocs)
+    in.extRelocs->finalizeContents();
+  if (in.localRelocs)
+    in.localRelocs->finalizeContents();
+
   // Now that __LINKEDIT is filled out, do a proper calculation of its
   // addresses and offsets.
   linkEditSegment->addr = addr;

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to