[llvm] [MachO] Preserve weak attributes on aliases (PR #219534)

via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 30 05:19:58 PDT 2026


https://github.com/AsakuraMizu updated https://github.com/llvm/llvm-project/pull/219534

>From 006b49a699e2b4b787580e0d36553ea6965d0e1e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9C=9D=E5=80=89=E6=B0=B4=E5=B8=8C?= <mizuk1 at mzk1.dev>
Date: Fri, 28 Aug 2026 22:45:30 +0800
Subject: [PATCH 1/2] [MachO] Preserve weak attributes on aliases

---
 llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp    |  4 +-
 llvm/lib/MC/MachObjectWriter.cpp              |  6 +-
 llvm/test/CodeGen/AArch64/macho-weak-alias.ll | 26 ++++++
 llvm/test/MC/MachO/weak-alias.s               | 84 +++++++++++++++++++
 4 files changed, 118 insertions(+), 2 deletions(-)
 create mode 100644 llvm/test/CodeGen/AArch64/macho-weak-alias.ll
 create mode 100644 llvm/test/MC/MachO/weak-alias.s

diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index dab57e744db08..67fb460086823 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -2702,7 +2702,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..ab76d0f94c57d 100644
--- a/llvm/lib/MC/MachObjectWriter.cpp
+++ b/llvm/lib/MC/MachObjectWriter.cpp
@@ -443,7 +443,11 @@ 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 = Symbol->getEncodedFlags(EncodeAsAltEntry);
+  if (IsAlias)
+    Flags |= OrigSymbol.getEncodedFlags(false) &
+             (MachO::N_WEAK_DEF | MachO::N_WEAK_REF);
+  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..13c3f3ec6cd11
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/macho-weak-alias.ll
@@ -0,0 +1,26 @@
+; RUN: llc -mtriple=aarch64-apple-macosx13.0.0 %s -o - | FileCheck %s
+
+ at foo = internal global i32 0
+ at external_alias = alias i32, ptr @foo
+ at internal_alias = internal alias i32, ptr @foo
+ at weak_alias = weak alias i32, ptr @foo
+ at hidden_weak_alias = weak hidden alias i32, ptr @foo
+ at linkonce_alias = linkonce alias i32, ptr @foo
+ at auto_hide_alias = linkonce_odr unnamed_addr alias i32, ptr @foo
+
+; CHECK:      .globl _external_alias
+; CHECK-NEXT: _external_alias = _foo
+; CHECK:      _internal_alias = _foo
+; CHECK:      .globl _weak_alias
+; CHECK-NEXT: .weak_definition _weak_alias
+; CHECK-NEXT: _weak_alias = _foo
+; CHECK:      .globl _hidden_weak_alias
+; CHECK-NEXT: .weak_definition _hidden_weak_alias
+; CHECK-NEXT: .private_extern _hidden_weak_alias
+; CHECK-NEXT: _hidden_weak_alias = _foo
+; CHECK:      .globl _linkonce_alias
+; CHECK-NEXT: .weak_definition _linkonce_alias
+; CHECK-NEXT: _linkonce_alias = _foo
+; CHECK:      .globl _auto_hide_alias
+; CHECK-NEXT: .weak_def_can_be_hidden _auto_hide_alias
+; CHECK-NEXT: _auto_hide_alias = _foo
diff --git a/llvm/test/MC/MachO/weak-alias.s b/llvm/test/MC/MachO/weak-alias.s
new file mode 100644
index 0000000000000..076abc3d2df87
--- /dev/null
+++ b/llvm/test/MC/MachO/weak-alias.s
@@ -0,0 +1,84 @@
+// RUN: llvm-mc -triple x86_64-apple-macosx13.0.0 -filetype=obj %s -o - | llvm-readobj --symbols - | FileCheck %s
+
+.text
+_foo:
+  nop
+
+.globl _external
+_external = _foo
+
+.globl _weak
+.weak_definition _weak
+_weak = _foo
+
+.globl _auto
+.weak_def_can_be_hidden _auto
+_auto = _foo
+
+_local = _foo
+
+.globl _weak_target
+.weak_definition _weak_target
+_weak_target:
+  nop
+
+.globl _strong_to_weak
+_strong_to_weak = _weak_target
+
+// CHECK:      Name: _local
+// CHECK-NEXT: Type: Section (0xE)
+// CHECK-NEXT: Section: __text (0x1)
+// CHECK-NEXT: RefType: UndefinedNonLazy (0x0)
+// CHECK-NEXT: Flags [ (0x0)
+// CHECK-NEXT: ]
+// CHECK-NEXT: Value: 0x0
+
+// CHECK:      Name: _auto
+// CHECK-NEXT: Extern
+// CHECK-NEXT: Type: Section (0xE)
+// CHECK-NEXT: Section: __text (0x1)
+// CHECK-NEXT: RefType: UndefinedNonLazy (0x0)
+// CHECK-NEXT: Flags [ (0xC0)
+// CHECK-NEXT:   WeakDef (0x80)
+// CHECK-NEXT:   WeakRef (0x40)
+// CHECK-NEXT: ]
+// CHECK-NEXT: Value: 0x0
+
+// CHECK:      Name: _external
+// CHECK-NEXT: Extern
+// CHECK-NEXT: Type: Section (0xE)
+// CHECK-NEXT: Section: __text (0x1)
+// CHECK-NEXT: RefType: UndefinedNonLazy (0x0)
+// CHECK-NEXT: Flags [ (0x0)
+// CHECK-NEXT: ]
+// CHECK-NEXT: Value: 0x0
+
+// CHECK:      Name: _strong_to_weak
+// CHECK-NEXT: Extern
+// CHECK-NEXT: Type: Section (0xE)
+// CHECK-NEXT: Section: __text (0x1)
+// CHECK-NEXT: RefType: UndefinedNonLazy (0x0)
+// CHECK-NEXT: Flags [ (0x80)
+// CHECK-NEXT:   WeakDef (0x80)
+// CHECK-NEXT: ]
+// CHECK-NEXT: Value: 0x1
+
+// CHECK:      Name: _weak
+// CHECK-NEXT: Extern
+// CHECK-NEXT: Type: Section (0xE)
+// CHECK-NEXT: Section: __text (0x1)
+// CHECK-NEXT: RefType: UndefinedNonLazy (0x0)
+// CHECK-NEXT: Flags [ (0x80)
+// CHECK-NEXT:   WeakDef (0x80)
+// CHECK-NEXT: ]
+// CHECK-NEXT: Value: 0x0
+
+// CHECK:      Name: _weak_target
+// CHECK-NEXT: Extern
+// CHECK-NEXT: Type: Section (0xE)
+// CHECK-NEXT: Section: __text (0x1)
+// CHECK-NEXT: RefType: UndefinedNonLazy (0x0)
+// CHECK-NEXT: Flags [ (0x80)
+// CHECK-NEXT:   WeakDef (0x80)
+// CHECK-NEXT: ]
+// CHECK-NEXT: Value: 0x1

>From 407d9757a0484a24cc132fbe898b4c1d31ee43f4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9C=9D=E5=80=89=E6=B0=B4=E5=B8=8C?= <mizuk1 at mzk1.dev>
Date: Sat, 5 Sep 2026 23:47:03 +0800
Subject: [PATCH 2/2] [MachO] Add alias flag tests

---
 llvm/test/MC/MachO/alias-flags.s | 177 +++++++++++++++++++++++++++++++
 1 file changed, 177 insertions(+)
 create mode 100644 llvm/test/MC/MachO/alias-flags.s

diff --git a/llvm/test/MC/MachO/alias-flags.s b/llvm/test/MC/MachO/alias-flags.s
new file mode 100644
index 0000000000000..cdff037548168
--- /dev/null
+++ b/llvm/test/MC/MachO/alias-flags.s
@@ -0,0 +1,177 @@
+// RUN: llvm-mc -triple x86_64-apple-macosx13.0.0 -filetype=obj %s -o - | llvm-readobj --symbols - | FileCheck %s
+
+// Aliases inherit these n_desc fields from their aliasees. Of these flags,
+// only N_ALT_ENTRY is also preserved when set on the alias itself.
+.text
+_plain:
+  nop
+
+.alt_entry _alt_entry_target
+_alt_entry_target:
+  nop
+
+.cold _cold_target
+_cold_target:
+  nop
+
+.no_dead_strip _no_dead_strip_target
+_no_dead_strip_target:
+  nop
+
+_reference_type_target:
+  nop
+// Set the reference type after the label, which would otherwise clear it.
+.desc _reference_type_target, 2
+
+.symbol_resolver _resolver_target
+_resolver_target:
+  nop
+
+.globl _alt_entry_on_alias
+.alt_entry _alt_entry_on_alias
+_alt_entry_on_alias = _plain
+
+.globl _alt_entry_on_target
+_alt_entry_on_target = _alt_entry_target
+
+.globl _cold_on_alias
+.cold _cold_on_alias
+_cold_on_alias = _plain
+
+.globl _cold_on_target
+_cold_on_target = _cold_target
+
+.globl _no_dead_strip_on_alias
+.no_dead_strip _no_dead_strip_on_alias
+_no_dead_strip_on_alias = _plain
+
+.globl _no_dead_strip_on_target
+_no_dead_strip_on_target = _no_dead_strip_target
+
+// Different reference types must not be ORed together: the aliasee wins.
+.globl _reference_type_both
+.desc _reference_type_both, 1
+_reference_type_both = _reference_type_target
+
+.globl _reference_type_on_alias
+.desc _reference_type_on_alias, 1
+_reference_type_on_alias = _plain
+
+.globl _reference_type_on_target
+_reference_type_on_target = _reference_type_target
+
+.globl _resolver_on_alias
+.symbol_resolver _resolver_on_alias
+_resolver_on_alias = _plain
+
+.globl _resolver_on_target
+_resolver_on_target = _resolver_target
+
+// Preserve the aliasee's alt-entry bit along with both weak bits on the alias.
+.globl _auto_to_alt_entry
+.weak_def_can_be_hidden _auto_to_alt_entry
+_auto_to_alt_entry = _alt_entry_target
+
+// Only the weak bits are taken from the alias, not its no-dead-strip bit.
+.globl _weak_no_dead_strip
+.weak_definition _weak_no_dead_strip
+.no_dead_strip _weak_no_dead_strip
+_weak_no_dead_strip = _plain
+
+// Preserve the aliasee's no-dead-strip bit when adding the alias's weak bit.
+.globl _weak_to_no_dead_strip
+.weak_definition _weak_to_no_dead_strip
+_weak_to_no_dead_strip = _no_dead_strip_target
+
+// CHECK-LABEL: Name: _alt_entry_on_alias
+// CHECK:       RefType: UndefinedNonLazy (0x0)
+// CHECK-NEXT:  Flags [ (0x200)
+// CHECK-NEXT:    AltEntry (0x200)
+// CHECK-NEXT:  ]
+
+// CHECK-LABEL: Name: _alt_entry_on_target
+// CHECK:       RefType: UndefinedNonLazy (0x0)
+// CHECK-NEXT:  Flags [ (0x200)
+// CHECK-NEXT:    AltEntry (0x200)
+// CHECK-NEXT:  ]
+
+// CHECK-LABEL: Name: _auto_to_alt_entry
+// CHECK-NEXT:  Extern
+// CHECK-NEXT:  Type: Section (0xE)
+// CHECK-NEXT:  Section: __text (0x1)
+// CHECK-NEXT:  RefType: UndefinedNonLazy (0x0)
+// CHECK-NEXT:  Flags [ (0x2C0)
+// CHECK-NEXT:    AltEntry (0x200)
+// CHECK-NEXT:    WeakDef (0x80)
+// CHECK-NEXT:    WeakRef (0x40)
+// CHECK-NEXT:  ]
+// CHECK-NEXT:  Value: 0x1
+
+// CHECK-LABEL: Name: _cold_on_alias
+// CHECK:       RefType: UndefinedNonLazy (0x0)
+// CHECK-NEXT:  Flags [ (0x0)
+// CHECK-NEXT:  ]
+
+// CHECK-LABEL: Name: _cold_on_target
+// CHECK:       RefType: UndefinedNonLazy (0x0)
+// CHECK-NEXT:  Flags [ (0x400)
+// CHECK-NEXT:    ColdFunc (0x400)
+// CHECK-NEXT:  ]
+
+// CHECK-LABEL: Name: _no_dead_strip_on_alias
+// CHECK:       RefType: UndefinedNonLazy (0x0)
+// CHECK-NEXT:  Flags [ (0x0)
+// CHECK-NEXT:  ]
+
+// CHECK-LABEL: Name: _no_dead_strip_on_target
+// CHECK:       RefType: UndefinedNonLazy (0x0)
+// CHECK-NEXT:  Flags [ (0x20)
+// CHECK-NEXT:    NoDeadStrip (0x20)
+// CHECK-NEXT:  ]
+
+// CHECK-LABEL: Name: _reference_type_both
+// CHECK:       RefType: ReferenceFlagDefined (0x2)
+// CHECK-NEXT:  Flags [ (0x0)
+// CHECK-NEXT:  ]
+
+// CHECK-LABEL: Name: _reference_type_on_alias
+// CHECK:       RefType: UndefinedNonLazy (0x0)
+// CHECK-NEXT:  Flags [ (0x0)
+// CHECK-NEXT:  ]
+
+// CHECK-LABEL: Name: _reference_type_on_target
+// CHECK:       RefType: ReferenceFlagDefined (0x2)
+// CHECK-NEXT:  Flags [ (0x0)
+// CHECK-NEXT:  ]
+
+// CHECK-LABEL: Name: _resolver_on_alias
+// CHECK:       RefType: UndefinedNonLazy (0x0)
+// CHECK-NEXT:  Flags [ (0x0)
+// CHECK-NEXT:  ]
+
+// CHECK-LABEL: Name: _resolver_on_target
+// CHECK:       RefType: UndefinedNonLazy (0x0)
+// CHECK-NEXT:  Flags [ (0x100)
+// CHECK-NEXT:    SymbolResolver (0x100)
+// CHECK-NEXT:  ]
+
+// CHECK-LABEL: Name: _weak_no_dead_strip
+// CHECK-NEXT:  Extern
+// CHECK-NEXT:  Type: Section (0xE)
+// CHECK-NEXT:  Section: __text (0x1)
+// CHECK-NEXT:  RefType: UndefinedNonLazy (0x0)
+// CHECK-NEXT:  Flags [ (0x80)
+// CHECK-NEXT:    WeakDef (0x80)
+// CHECK-NEXT:  ]
+// CHECK-NEXT:  Value: 0x0
+
+// CHECK-LABEL: Name: _weak_to_no_dead_strip
+// CHECK-NEXT:  Extern
+// CHECK-NEXT:  Type: Section (0xE)
+// CHECK-NEXT:  Section: __text (0x1)
+// CHECK-NEXT:  RefType: UndefinedNonLazy (0x0)
+// CHECK-NEXT:  Flags [ (0xA0)
+// CHECK-NEXT:    NoDeadStrip (0x20)
+// CHECK-NEXT:    WeakDef (0x80)
+// CHECK-NEXT:  ]
+// CHECK-NEXT:  Value: 0x3



More information about the llvm-commits mailing list