[llvm] [llvm] Support IFuncs on Darwin platforms (PR #73686)

via llvm-commits llvm-commits at lists.llvm.org
Tue Nov 28 10:40:25 PST 2023


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-x86

Author: Jon Roelofs (jroelofs)

<details>
<summary>Changes</summary>

... by lowering them as lazy resolve-on-first-use symbol resolvers. Note that
this is subtly different timing than on ELF platforms, where ifunc resolution
happens at load time.

Since ld64 and ld-prime don't support all the cases we need for these, there is
a manual fallback lowering.


---

Patch is 29.31 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/73686.diff


12 Files Affected:

- (modified) llvm/docs/LangRef.rst (+4-3) 
- (modified) llvm/include/llvm/CodeGen/AsmPrinter.h (+5-1) 
- (modified) llvm/lib/CodeGen/GlobalISel/CallLowering.cpp (+6-1) 
- (modified) llvm/lib/IR/Verifier.cpp (+5-7) 
- (modified) llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp (+308) 
- (modified) llvm/lib/Target/X86/X86AsmPrinter.cpp (+28) 
- (modified) llvm/lib/Target/X86/X86AsmPrinter.h (+1) 
- (added) llvm/test/CodeGen/AArch64/GlobalISel/call-lowering-ifunc.ll (+37) 
- (modified) llvm/test/CodeGen/AArch64/addrsig-macho.ll (+2-2) 
- (added) llvm/test/CodeGen/AArch64/ifunc-asm.ll (+82) 
- (modified) llvm/test/CodeGen/X86/ifunc-asm.ll (+19-9) 
- (added) llvm/test/Verifier/ifunc-macho.ll (+42) 


``````````diff
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index e448c5ed5c5d947..cb222e979db29d4 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -934,10 +934,11 @@ IFuncs
 -------
 
 IFuncs, like as aliases, don't create any new data or func. They are just a new
-symbol that dynamic linker resolves at runtime by calling a resolver function.
+symbol that is resolved at runtime by calling a resolver function.
 
-IFuncs have a name and a resolver that is a function called by dynamic linker
-that returns address of another function associated with the name.
+On ELF platforms, IFuncs are resolved by the dynamic linker at load time. On
+MachO platforms, they are lowered in terms of ``.symbol_resolver``s, which
+lazily resolve the callee the first time they are called.
 
 IFunc may have an optional :ref:`linkage type <linkage>` and an optional
 :ref:`visibility style <visibility>`.
diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h
index 2731ef452c79cbb..48fa6c478464c73 100644
--- a/llvm/include/llvm/CodeGen/AsmPrinter.h
+++ b/llvm/include/llvm/CodeGen/AsmPrinter.h
@@ -882,7 +882,11 @@ class AsmPrinter : public MachineFunctionPass {
 
   GCMetadataPrinter *getOrCreateGCPrinter(GCStrategy &S);
   void emitGlobalAlias(Module &M, const GlobalAlias &GA);
-  void emitGlobalIFunc(Module &M, const GlobalIFunc &GI);
+
+protected:
+  virtual void emitGlobalIFunc(Module &M, const GlobalIFunc &GI);
+
+private:
 
   /// This method decides whether the specified basic block requires a label.
   bool shouldEmitLabelForBasicBlock(const MachineBasicBlock &MBB) const;
diff --git a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp
index 2527b1431289677..e0080b145d4f995 100644
--- a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp
@@ -144,7 +144,12 @@ bool CallLowering::lowerCall(MachineIRBuilder &MIRBuilder, const CallBase &CB,
   // Try looking through a bitcast from one function type to another.
   // Commonly happens with calls to objc_msgSend().
   const Value *CalleeV = CB.getCalledOperand()->stripPointerCasts();
-  if (const Function *F = dyn_cast<Function>(CalleeV))
+  if (const GlobalIFunc *IF = dyn_cast<GlobalIFunc>(CalleeV);
+      IF && MF.getTarget().getTargetTriple().isOSBinFormatMachO()) {
+    // ld64 requires that .symbol_resolvers to be called via a stub, so these
+    // must always be a diret call.
+    Info.Callee = MachineOperand::CreateGA(IF, 0);
+  } else if (const Function *F = dyn_cast<Function>(CalleeV))
     Info.Callee = MachineOperand::CreateGA(F, 0);
   else
     Info.Callee = MachineOperand::CreateReg(GetCalleeReg(), false);
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 5560c037aa3ee6b..94e76a43bf38d6d 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -959,6 +959,7 @@ void Verifier::visitGlobalIFunc(const GlobalIFunc &GI) {
       GlobalIFunc::getResolverFunctionType(GI.getValueType());
   Check(ResolverTy == ResolverFuncTy->getPointerTo(GI.getAddressSpace()),
         "IFunc resolver has incorrect type", &GI);
+
 }
 
 void Verifier::visitNamedMDNode(const NamedMDNode &NMD) {
@@ -2239,13 +2240,10 @@ void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs,
   }
 
   // Check EVEX512 feature.
-  if (MaxParameterWidth >= 512 && Attrs.hasFnAttr("target-features")) {
-    Triple T(M.getTargetTriple());
-    if (T.isX86()) {
-      StringRef TF = Attrs.getFnAttr("target-features").getValueAsString();
-      Check(!TF.contains("+avx512f") || !TF.contains("-evex512"),
-            "512-bit vector arguments require 'evex512' for AVX512", V);
-    }
+  if (MaxParameterWidth >= 512 && Attrs.hasFnAttr("target-features") && TT.isX86()) {
+    StringRef TF = Attrs.getFnAttr("target-features").getValueAsString();
+    Check(!TF.contains("+avx512f") || !TF.contains("-evex512"),
+          "512-bit vector arguments require 'evex512' for AVX512", V);
   }
 
   checkUnsignedBaseTenFuncAttr(Attrs, "patchable-function-prefix", V);
diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
index f4d3a85f34c88da..2dab8e126c9abd0 100644
--- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
+++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
@@ -30,6 +30,7 @@
 #include "llvm/ADT/Twine.h"
 #include "llvm/BinaryFormat/COFF.h"
 #include "llvm/BinaryFormat/ELF.h"
+#include "llvm/BinaryFormat/MachO.h"
 #include "llvm/CodeGen/AsmPrinter.h"
 #include "llvm/CodeGen/FaultMaps.h"
 #include "llvm/CodeGen/MachineBasicBlock.h"
@@ -47,10 +48,12 @@
 #include "llvm/MC/MCInst.h"
 #include "llvm/MC/MCInstBuilder.h"
 #include "llvm/MC/MCSectionELF.h"
+#include "llvm/MC/MCSectionMachO.h"
 #include "llvm/MC/MCStreamer.h"
 #include "llvm/MC/MCSymbol.h"
 #include "llvm/MC/TargetRegistry.h"
 #include "llvm/Support/Casting.h"
+#include "llvm/Support/CommandLine.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Target/TargetMachine.h"
@@ -68,6 +71,22 @@ using namespace llvm;
 
 namespace {
 
+enum class IFuncLowering { SymbolResolverIfSupported, SymbolResolverAlways, SymbolResolverNever };
+
+static cl::opt<IFuncLowering> PreferredIFuncLowering(
+    "arm64-darwin-ifunc-symbol_resolver", cl::init(IFuncLowering::SymbolResolverNever),
+    cl::desc("Pick the lowering for ifuncs on darwin platforms"), cl::Hidden,
+    cl::values(
+        clEnumValN(
+            IFuncLowering::SymbolResolverIfSupported, "if_supported",
+            "Use .symbol_resolver's when known to be supported by the linker."),
+        clEnumValN(IFuncLowering::SymbolResolverAlways, "always",
+                   "Always use .symbol_resolvers. NOTE: this might not be "
+                   "supported by the linker in all cases."),
+        clEnumValN(IFuncLowering::SymbolResolverNever, "never",
+                   "Use a manual lowering, doing what the linker would have "
+                   "done, but in the compiler.")));
+
 class AArch64AsmPrinter : public AsmPrinter {
   AArch64MCInstLower MCInstLowering;
   FaultMaps FM;
@@ -198,6 +217,11 @@ class AArch64AsmPrinter : public AsmPrinter {
   bool shouldEmitWeakSwiftAsyncExtendedFramePointerFlags() const override {
     return ShouldEmitWeakSwiftAsyncExtendedFramePointerFlags;
   }
+
+  void emitGlobalIFunc(Module &M, const GlobalIFunc &GI) override;
+
+  void emitLinkerSymbolResolver(Module &M, const GlobalIFunc &GI);
+  void emitManualSymbolResolver(Module &M, const GlobalIFunc &GI);
 };
 
 } // end anonymous namespace
@@ -1809,6 +1833,290 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) {
   EmitToStreamer(*OutStreamer, TmpInst);
 }
 
+void AArch64AsmPrinter::emitLinkerSymbolResolver(Module &M,
+                                                 const GlobalIFunc &GI) {
+  OutStreamer->switchSection(OutContext.getObjectFileInfo()->getTextSection());
+
+  MCSymbol *Name = getSymbol(&GI);
+
+  // NOTE: non-global .symbol_resolvers are not yet supported by Darwin linkers
+
+  if (GI.hasExternalLinkage() || !MAI->getWeakRefDirective())
+    OutStreamer->emitSymbolAttribute(Name, MCSA_Global);
+  else if (GI.hasWeakLinkage() || GI.hasLinkOnceLinkage())
+    OutStreamer->emitSymbolAttribute(Name, MCSA_WeakReference);
+  else
+    assert(GI.hasLocalLinkage() && "Invalid ifunc linkage");
+
+  OutStreamer->emitCodeAlignment(Align(4), STI);
+  OutStreamer->emitLabel(Name);
+  OutStreamer->emitSymbolAttribute(Name, MCSA_SymbolResolver);
+  emitVisibility(Name, GI.getVisibility());
+
+  // ld-prime does not seem to support aliases of symbol resolvers, so we have to
+  // tail call the resolver manually.
+  OutStreamer->emitInstruction(
+      MCInstBuilder(AArch64::B)
+          .addOperand(MCOperand::createExpr(lowerConstant(GI.getResolver()))),
+      *STI);
+}
+
+/// \brief Emit a manually-constructed .symbol_resolver that implements the
+/// symbol resolution duties of the IFunc.
+///
+/// Normally, this would be handled by linker magic, but unfortunately there are
+/// a few limitations in ld64 and ld-prime's implementation of .symbol_resolver
+/// that mean we can't always use them:
+///
+///    *  resolvers cannot be the target of an alias
+///    *  resolvers cannot have private linkage
+///    *  resolvers cannot have linkonce linkage
+///    *  resolvers cannot appear in executables
+///    *  resolvers cannot appear in bundles
+///
+/// This works around that by emitting a close approximation of what the linker
+/// would have done.
+void AArch64AsmPrinter::emitManualSymbolResolver(Module &M,
+                                                 const GlobalIFunc &GI) {
+  auto EmitLinkage = [&](MCSymbol *Sym) {
+    if (GI.hasExternalLinkage() || !MAI->getWeakRefDirective())
+      OutStreamer->emitSymbolAttribute(Sym, MCSA_Global);
+    else if (GI.hasWeakLinkage() || GI.hasLinkOnceLinkage())
+      OutStreamer->emitSymbolAttribute(Sym, MCSA_WeakReference);
+    else
+      assert(GI.hasLocalLinkage() && "Invalid ifunc linkage");
+  };
+
+  MCSymbol *LazyPointer = TM.getObjFileLowering()->getContext().getOrCreateSymbol(
+      "_" + GI.getName() + ".lazy_pointer");
+  MCSymbol *StubHelper =
+      TM.getObjFileLowering()->getContext().getOrCreateSymbol(
+          "_" + GI.getName() + ".stub_helper");
+
+  OutStreamer->switchSection(OutContext.getObjectFileInfo()->getDataSection());
+
+  EmitLinkage(LazyPointer);
+  OutStreamer->emitLabel(LazyPointer);
+  emitVisibility(LazyPointer, GI.getVisibility());
+  OutStreamer->emitValue(MCSymbolRefExpr::create(StubHelper, OutContext), 8);
+
+  OutStreamer->switchSection(OutContext.getObjectFileInfo()->getTextSection());
+
+  MCSymbol *Stub = getSymbol(&GI);
+
+  EmitLinkage(Stub);
+  OutStreamer->emitCodeAlignment(Align(4), STI);
+  OutStreamer->emitLabel(Stub);
+  emitVisibility(Stub, GI.getVisibility());
+
+  // adrp	x16, lazy_pointer at GOTPAGE
+  // ldr	x16, [x16, lazy_pointer at GOTPAGEOFF]
+  // ldr	x16, [x16]
+  // br	x16
+
+  {
+    MCInst Adrp;
+    Adrp.setOpcode(AArch64::ADRP);
+    Adrp.addOperand(MCOperand::createReg(AArch64::X16));
+    MCOperand SymPage;
+    MCInstLowering.lowerOperand(
+        MachineOperand::CreateES(LazyPointer->getName().data() + 1,
+                                 AArch64II::MO_GOT | AArch64II::MO_PAGE),
+        SymPage);
+    Adrp.addOperand(SymPage);
+    OutStreamer->emitInstruction(Adrp, *STI);
+  }
+
+  {
+    MCInst Ldr;
+    Ldr.setOpcode(AArch64::LDRXui);
+    Ldr.addOperand(MCOperand::createReg(AArch64::X16));
+    Ldr.addOperand(MCOperand::createReg(AArch64::X16));
+    MCOperand SymPageOff;
+    MCInstLowering.lowerOperand(
+        MachineOperand::CreateES(LazyPointer->getName().data() + 1,
+                                 AArch64II::MO_GOT | AArch64II::MO_PAGEOFF),
+        SymPageOff);
+    Ldr.addOperand(SymPageOff);
+    Ldr.addOperand(MCOperand::createImm(0));
+    OutStreamer->emitInstruction(Ldr, *STI);
+  }
+
+  OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDRXui)
+    .addReg(AArch64::X16)
+    .addReg(AArch64::X16)
+    .addImm(0), *STI);
+
+  OutStreamer->emitInstruction(MCInstBuilder(TM.getTargetTriple().isArm64e()
+                                                 ? AArch64::BRAAZ
+                                                 : AArch64::BR)
+                                   .addReg(AArch64::X16),
+                               *STI);
+
+  EmitLinkage(StubHelper);
+  OutStreamer->emitCodeAlignment(Align(4), STI);
+  OutStreamer->emitLabel(StubHelper);
+  emitVisibility(StubHelper, GI.getVisibility());
+
+  // stp	fp, lr, [sp, #-16]!
+  // mov	fp, sp
+  // stp	x1, x0, [sp, #-16]!
+  // stp	x3, x2, [sp, #-16]!
+  // stp	x5, x4, [sp, #-16]!
+  // stp	x7, x6, [sp, #-16]!
+  // stp	d1, d0, [sp, #-16]!
+  // stp	d3, d2, [sp, #-16]!
+  // stp	d5, d4, [sp, #-16]!
+  // stp	d7, d6, [sp, #-16]!
+  // bl	_resolver
+  // adrp	x16, lazy_pointer at GOTPAGE
+  // ldr	x16, [x16, lazy_pointer at GOTPAGEOFF]
+  // str	x0, [x16]
+  // mov	x16, x0
+  // ldp	d7, d6, [sp], #16
+  // ldp	d5, d4, [sp], #16
+  // ldp	d3, d2, [sp], #16
+  // ldp	d1, d0, [sp], #16
+  // ldp	x7, x6, [sp], #16
+  // ldp	x5, x4, [sp], #16
+  // ldp	x3, x2, [sp], #16
+  // ldp	x1, x0, [sp], #16
+  // ldp	fp, lr, [sp], #16
+  // br	x16
+
+  OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXpre)
+                                   .addReg(AArch64::SP)
+                                   .addReg(AArch64::FP)
+                                   .addReg(AArch64::LR)
+                                   .addReg(AArch64::SP)
+                                   .addImm(-2),
+                               *STI);
+
+  OutStreamer->emitInstruction(MCInstBuilder(AArch64::ADDXri)
+                                   .addReg(AArch64::FP)
+                                   .addReg(AArch64::SP)
+                                   .addImm(0)
+                                   .addImm(0),
+                               *STI);
+
+  for (int I = 0; I != 4; ++I)
+    OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXpre)
+                                     .addReg(AArch64::SP)
+                                     .addReg(AArch64::X1 + 2 * I)
+                                     .addReg(AArch64::X0 + 2 * I)
+                                     .addReg(AArch64::SP)
+                                     .addImm(-2),
+                                 *STI);
+
+  for (int I = 0; I != 4; ++I)
+    OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPDpre)
+                                     .addReg(AArch64::SP)
+                                     .addReg(AArch64::D1 + 2 * I)
+                                     .addReg(AArch64::D0 + 2 * I)
+                                     .addReg(AArch64::SP)
+                                     .addImm(-2),
+                                 *STI);
+
+  OutStreamer->emitInstruction(
+      MCInstBuilder(AArch64::BL)
+          .addOperand(MCOperand::createExpr(lowerConstant(GI.getResolver()))),
+      *STI);
+
+  {
+    MCInst Adrp;
+    Adrp.setOpcode(AArch64::ADRP);
+    Adrp.addOperand(MCOperand::createReg(AArch64::X16));
+    MCOperand SymPage;
+    MCInstLowering.lowerOperand(
+        MachineOperand::CreateES(LazyPointer->getName().data() + 1,
+                                 AArch64II::MO_GOT | AArch64II::MO_PAGE),
+        SymPage);
+    Adrp.addOperand(SymPage);
+    OutStreamer->emitInstruction(Adrp, *STI);
+  }
+
+  {
+    MCInst Ldr;
+    Ldr.setOpcode(AArch64::LDRXui);
+    Ldr.addOperand(MCOperand::createReg(AArch64::X16));
+    Ldr.addOperand(MCOperand::createReg(AArch64::X16));
+    MCOperand SymPageOff;
+    MCInstLowering.lowerOperand(
+        MachineOperand::CreateES(LazyPointer->getName().data() + 1,
+                                 AArch64II::MO_GOT | AArch64II::MO_PAGEOFF),
+        SymPageOff);
+    Ldr.addOperand(SymPageOff);
+    Ldr.addOperand(MCOperand::createImm(0));
+    OutStreamer->emitInstruction(Ldr, *STI);
+  }
+
+  OutStreamer->emitInstruction(MCInstBuilder(AArch64::STRXui)
+                                   .addReg(AArch64::X0)
+                                   .addReg(AArch64::X16)
+                                   .addImm(0),
+                               *STI);
+
+  OutStreamer->emitInstruction(MCInstBuilder(AArch64::ADDXri)
+                                   .addReg(AArch64::X16)
+                                   .addReg(AArch64::X0)
+                                   .addImm(0)
+                                   .addImm(0),
+                               *STI);
+
+  for (int I = 3; I != -1; --I)
+    OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPDpost)
+                                     .addReg(AArch64::SP)
+                                     .addReg(AArch64::D1 + 2 * I)
+                                     .addReg(AArch64::D0 + 2 * I)
+                                     .addReg(AArch64::SP)
+                                     .addImm(2),
+                                 *STI);
+
+  for (int I = 3; I != -1; --I)
+    OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPXpost)
+                                     .addReg(AArch64::SP)
+                                     .addReg(AArch64::X1 + 2 * I)
+                                     .addReg(AArch64::X0 + 2 * I)
+                                     .addReg(AArch64::SP)
+                                     .addImm(2),
+                                 *STI);
+
+  OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPXpost)
+                                   .addReg(AArch64::SP)
+                                   .addReg(AArch64::FP)
+                                   .addReg(AArch64::LR)
+                                   .addReg(AArch64::SP)
+                                   .addImm(2),
+                               *STI);
+
+  OutStreamer->emitInstruction(MCInstBuilder(TM.getTargetTriple().isArm64e()
+                                                 ? AArch64::BRAAZ
+                                                 : AArch64::BR)
+                                   .addReg(AArch64::X16),
+                               *STI);
+}
+
+void AArch64AsmPrinter::emitGlobalIFunc(Module &M, const GlobalIFunc &GI) {
+  if (!TM.getTargetTriple().isOSBinFormatMachO())
+    return AsmPrinter::emitGlobalIFunc(M, GI);
+
+  switch (PreferredIFuncLowering) {
+  case IFuncLowering::SymbolResolverAlways:
+    return emitLinkerSymbolResolver(M, GI);
+  case IFuncLowering::SymbolResolverNever:
+    return emitManualSymbolResolver(M, GI);
+  case IFuncLowering::SymbolResolverIfSupported:
+    if (GI.hasExternalLinkage() || !MAI->getWeakRefDirective())
+      return emitLinkerSymbolResolver(M, GI);
+    else if (GI.hasWeakLinkage() || GI.hasLinkOnceLinkage())
+      // NOTE: non-global .symbol_resolvers are not yet supported by Darwin
+      // linkers
+      return emitManualSymbolResolver(M, GI);
+    else
+      assert(GI.hasLocalLinkage() && "Invalid ifunc linkage");
+  }
+}
+
 // Force static initialization.
 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeAArch64AsmPrinter() {
   RegisterAsmPrinter<AArch64AsmPrinter> X(getTheAArch64leTarget());
diff --git a/llvm/lib/Target/X86/X86AsmPrinter.cpp b/llvm/lib/Target/X86/X86AsmPrinter.cpp
index 73c7450620966cd..5241aa6e1c0eade 100644
--- a/llvm/lib/Target/X86/X86AsmPrinter.cpp
+++ b/llvm/lib/Target/X86/X86AsmPrinter.cpp
@@ -530,6 +530,34 @@ void X86AsmPrinter::PrintIntelMemReference(const MachineInstr *MI,
   O << ']';
 }
 
+void X86AsmPrinter::emitGlobalIFunc(Module &M, const GlobalIFunc &GI) {
+  if (!TM.getTargetTriple().isOSBinFormatMachO())
+    return AsmPrinter::emitGlobalIFunc(M, GI);
+
+  OutStreamer->switchSection(OutContext.getObjectFileInfo()->getTextSection());
+
+  MCSymbol *Name = getSymbol(&GI);
+
+  if (GI.hasExternalLinkage() || !MAI->getWeakRefDirective())
+    OutStreamer->emitSymbolAttribute(Name, MCSA_Global);
+  else if (GI.hasWeakLinkage() || GI.hasLinkOnceLinkage())
+    OutStreamer->emitSymbolAttribute(Name, MCSA_WeakReference);
+  else
+    assert(GI.hasLocalLinkage() && "Invalid ifunc linkage");
+
+  OutStreamer->emitCodeAlignment(Align(16), Subtarget);
+  OutStreamer->emitLabel(Name);
+  OutStreamer->emitSymbolAttribute(Name, MCSA_SymbolResolver);
+  emitVisibility(Name, GI.getVisibility());
+
+  // ld64 does not seem to support aliases of symbol resolvers, so we have to
+  // tail call the resolver manually.
+  MCInst JMP;
+  JMP.setOpcode(X86::JMP_4);
+  JMP.addOperand(MCOperand::createExpr(lowerConstant(GI.getResolver())));
+  OutStreamer->emitInstruction(JMP, *Subtarget);
+}
+
 static bool printAsmMRegister(const X86AsmPrinter &P, const MachineOperand &MO,
                               char Mode, raw_ostream &O) {
   Register Reg = MO.getReg();
diff --git a/llvm/lib/Target/X86/X86AsmPrinter.h b/llvm/lib/Target/X86/X86AsmPrinter.h
index c81651cf7f2f0e6..47f3b7c00c99ddb 100644
--- a/llvm/lib/Target/X86/X86AsmPrinter.h
+++ b/llvm/lib/Target/X86/X86AsmPrinter.h
@@ -120,6 +120,7 @@ class LLVM_LIBRARY_VISIBILITY X86AsmPrinter : public AsmPrinter {
                          const char *Modifier);
   void PrintIntelMemReference(const MachineInstr *MI, unsigned OpNo,
                               raw_ostream &O, const char *Modifier);
+  void emitGlobalIFunc(Module &M, const GlobalIFunc &GI) override;
 
 public:
   X86AsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer);
...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/73686


More information about the llvm-commits mailing list