[llvm] [MachO] Refine alias n_desc flag ownership (name flags from alias, not aliasee) (PR #212001)

via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 14 19:03:59 PDT 2026


https://github.com/syhhyl updated https://github.com/llvm/llvm-project/pull/212001

>From 19d2845a636690d721c14d685115afea9cd9a8e3 Mon Sep 17 00:00:00 2001
From: syhhyl <syhhyl926 at 126.com>
Date: Sat, 15 Aug 2026 10:02:01 +0800
Subject: [PATCH] [MachO] Preserve weak aliases and fix alias n_desc flags

Weak aliases must be emitted with a proper global definition so they are
publicly linkable on Darwin (issue #111321). Restore the emitGlobalAlias
Mach-O path that gives aliases their linkage before emitting them.

When writing the n_desc for an alias, take the name attributes
(N_WEAK_DEF, N_WEAK_REF, N_ALT_ENTRY, N_NO_DEAD_STRIP) from the alias
itself and only inherit the location attributes from the aliasee. This
keeps weak aliases weak without propagating a weak aliasee's definition
to strong aliases, which caused the previous fix (reverted in #212009)
to mis-flag strong aliases as weak definitions.
---
 llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp    |  4 +-
 llvm/lib/MC/MachObjectWriter.cpp              | 16 +++-
 llvm/test/CodeGen/AArch64/macho-weak-alias.ll | 82 +++++++++++++++++++
 3 files changed, 100 insertions(+), 2 deletions(-)
 create mode 100644 llvm/test/CodeGen/AArch64/macho-weak-alias.ll

diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 8f8ccd0d2b253..61103a1ecbffa 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -2667,7 +2667,9 @@ void AsmPrinter::emitGlobalAlias(const Module &M, const GlobalAlias &GA) {
     return;
   }
 
-  if (GA.hasExternalLinkage() || !MAI.getWeakRefDirective())
+  if (MAI.isMachO())
+    emitLinkage(&GA, Name);
+  else if (GA.hasExternalLinkage() || !MAI.getWeakRefDirective())
     OutStreamer->emitSymbolAttribute(Name, MCSA_Global);
   else if (GA.hasWeakLinkage() || GA.hasLinkOnceLinkage())
     OutStreamer->emitSymbolAttribute(Name, MCSA_WeakReference);
diff --git a/llvm/lib/MC/MachObjectWriter.cpp b/llvm/lib/MC/MachObjectWriter.cpp
index 790f7595807b9..2f1ed05be1b4e 100644
--- a/llvm/lib/MC/MachObjectWriter.cpp
+++ b/llvm/lib/MC/MachObjectWriter.cpp
@@ -443,7 +443,21 @@ void MachObjectWriter::writeNlist(MachSymbolData &MSD, const MCAssembler &Asm) {
   // The Mach-O streamer uses the lowest 16-bits of the flags for the 'desc'
   // value.
   bool EncodeAsAltEntry = IsAlias && OrigSymbol.isAltEntry();
-  W.write<uint16_t>(Symbol->getEncodedFlags(EncodeAsAltEntry));
+  uint16_t Flags;
+  if (!IsAlias) {
+    Flags = Symbol->getEncodedFlags(EncodeAsAltEntry);
+  } else {
+    uint16_t AliaseeFlags = Symbol->getEncodedFlags(false);
+    uint16_t AliasFlags = OrigSymbol.getEncodedFlags(EncodeAsAltEntry);
+    // For alias symbols the n_desc mixes name attributes (from the alias) and
+    // location attributes (from the aliasee). Take the name attributes from
+    // the alias so, e.g., a weak alias keeps N_WEAK_DEF without propagating
+    // the aliasee's weak definition to strong aliases.
+    constexpr uint16_t NameMask = MachO::N_WEAK_DEF | MachO::N_WEAK_REF |
+                                  MachO::N_ALT_ENTRY | MachO::N_NO_DEAD_STRIP;
+    Flags = (AliaseeFlags & ~NameMask) | (AliasFlags & NameMask);
+  }
+  W.write<uint16_t>(Flags);
   if (is64Bit())
     W.write<uint64_t>(Address);
   else
diff --git a/llvm/test/CodeGen/AArch64/macho-weak-alias.ll b/llvm/test/CodeGen/AArch64/macho-weak-alias.ll
new file mode 100644
index 0000000000000..b8fe3d600b168
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/macho-weak-alias.ll
@@ -0,0 +1,82 @@
+; RUN: llc -mtriple=aarch64-apple-macosx13.0.0 -filetype=obj %s -o %t.o
+; RUN: llvm-nm -m %t.o | FileCheck --check-prefix=NM %s
+; RUN: llvm-readobj --symbols %t.o | FileCheck --check-prefix=SYMBOL %s
+
+; llvm.used gives foo_internal N_NO_DEAD_STRIP.
+; Under the name-flag rule, aliases must NOT inherit it.
+ at llvm.used = appending global [1 x ptr] [ptr @foo_internal], section "llvm.metadata"
+
+define internal void @foo_internal() {
+  ret void
+}
+
+; Weak alias to internal target: bar sets N_WEAK_DEF, foo has N_NO_DEAD_STRIP.
+; Result: N_WEAK_DEF only (0x80), no N_NO_DEAD_STRIP.
+ at foo_default = weak_odr alias void (), ptr @foo_internal
+
+; Weak hidden alias: bar sets N_WEAK_DEF + hidden.
+ at foo_hidden = weak_odr hidden alias void (), ptr @foo_internal
+
+; Baseline: ordinary weak hidden definition.
+define weak_odr hidden void @foo_defined() {
+  ret void
+}
+
+; Weak aliasee target.
+define weak_odr void @foo_weak_aliasee() {
+  ret void
+}
+
+; Strong alias to weak target: bar has no weak, foo has N_WEAK_DEF.
+; Result: no weak flags (0x0).
+ at foo_strong_alias = alias void (), ptr @foo_weak_aliasee
+
+; Auto-hide weak: linkonce_odr unnamed_addr -> emit .weak_def_can_be_hidden.
+; Result: N_WEAK_DEF | N_WEAK_REF (0xC0).
+ at foo_auto = linkonce_odr unnamed_addr alias void (), ptr @foo_internal
+
+; NM-DAG: weak external _foo_default
+; NM-DAG: weak private external _foo_hidden
+; NM-DAG: weak private external _foo_defined
+; NM-DAG: {{^[0-9a-fA-F]+ \(__TEXT,__text\) external _foo_strong_alias$}}
+; NM-DAG: weak external automatically hidden _foo_auto
+; NM-DAG: non-external [no dead strip] _foo_internal
+
+; _foo_internal: N_NO_DEAD_STRIP from llvm.used (0x20).
+; SYMBOL:      Name: _foo_internal
+; SYMBOL-NEXT: Type: Section (0xE)
+; SYMBOL-NEXT: Section: __text
+; SYMBOL-NEXT: RefType: UndefinedNonLazy (0x0)
+; SYMBOL-NEXT: Flags [ (0x20)
+; SYMBOL-NEXT:   NoDeadStrip (0x20)
+; SYMBOL-NEXT: ]
+
+; _foo_auto: 0xC0 = N_WEAK_DEF | N_WEAK_REF.
+; SYMBOL:      Name: _foo_auto
+; SYMBOL-NEXT: Extern
+; SYMBOL-NEXT: Type: Section (0xE)
+; SYMBOL-NEXT: Section: __text
+; SYMBOL-NEXT: RefType: UndefinedNonLazy (0x0)
+; SYMBOL-NEXT: Flags [ (0xC0)
+; SYMBOL-NEXT:   WeakDef (0x80)
+; SYMBOL-NEXT:   WeakRef (0x40)
+; SYMBOL-NEXT: ]
+
+; _foo_default: 0x80 = N_WEAK_DEF, no N_NO_DEAD_STRIP inherited.
+; SYMBOL:      Name: _foo_default
+; SYMBOL-NEXT: Extern
+; SYMBOL-NEXT: Type: Section (0xE)
+; SYMBOL-NEXT: Section: __text
+; SYMBOL-NEXT: RefType: UndefinedNonLazy (0x0)
+; SYMBOL-NEXT: Flags [ (0x80)
+; SYMBOL-NEXT:   WeakDef (0x80)
+; SYMBOL-NEXT: ]
+
+; _foo_strong_alias: 0x0, no weak inherited from foo.
+; SYMBOL:      Name: _foo_strong_alias
+; SYMBOL-NEXT: Extern
+; SYMBOL-NEXT: Type: Section (0xE)
+; SYMBOL-NEXT: Section: __text
+; SYMBOL-NEXT: RefType: UndefinedNonLazy (0x0)
+; SYMBOL-NEXT: Flags [ (0x0)
+; SYMBOL-NEXT: ]
\ No newline at end of file



More information about the llvm-commits mailing list