Skip to content

[MachO] Preserve weak linkage for aliases#198148

Open
syhhyl wants to merge 1 commit into
llvm:mainfrom
syhhyl:fix-196047-macho-weak-alias
Open

[MachO] Preserve weak linkage for aliases#198148
syhhyl wants to merge 1 commit into
llvm:mainfrom
syhhyl:fix-196047-macho-weak-alias

Conversation

@syhhyl
Copy link
Copy Markdown

@syhhyl syhhyl commented May 17, 2026

Mach-O aliases with weak or linkonce linkage were emitted as weak references, which is appropriate for undefined references but not for alias definitions. Emit Mach-O aliases through the same linkage path as other global definitions so weak aliases get .weak_definition.

When writing aliased symbols, keep the aliasee flags and include the alias symbol's own flags so N_WEAK_DEF is preserved in the Mach-O n_desc field.

Fixes #196047 #111321

@llvmorg-github-actions
Copy link
Copy Markdown

@llvm/pr-subscribers-llvm-mc

Author: syhhyl (syhhyl)

Changes

Mach-O aliases with weak or linkonce linkage were emitted as weak references, which is appropriate for undefined references but not for alias definitions. Emit Mach-O aliases through the same linkage path as other global definitions so weak aliases get .weak_definition.

When writing aliased symbols, keep the aliasee flags and include the alias symbol's own flags so N_WEAK_DEF is preserved in the Mach-O n_desc field.

Fixes #196047


Full diff: https://github.com/llvm/llvm-project/pull/198148.diff

3 Files Affected:

  • (modified) llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp (+3-1)
  • (modified) llvm/lib/MC/MachObjectWriter.cpp (+4-1)
  • (added) llvm/test/CodeGen/AArch64/macho-weak-alias.ll (+17)
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 17fd80e81a673..8c3d69ee43200 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -2640,7 +2640,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 b42155d18bf0a..0786ca0e3a83b 100644
--- a/llvm/lib/MC/MachObjectWriter.cpp
+++ b/llvm/lib/MC/MachObjectWriter.cpp
@@ -443,7 +443,10 @@ 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(EncodeAsAltEntry);
+  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..a936cea618b38
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/macho-weak-alias.ll
@@ -0,0 +1,17 @@
+; RUN: llc -mtriple=aarch64-apple-macosx13.0.0 -filetype=obj %s -o %t.o
+; RUN: llvm-nm -m %t.o | FileCheck %s
+
+define internal void @foo_internal() {
+  ret void
+}
+
+@foo_default = weak_odr alias void (), ptr @foo_internal
+@foo_hidden = weak_odr hidden alias void (), ptr @foo_internal
+
+define weak_odr hidden void @foo_defined() {
+  ret void
+}
+
+; CHECK-DAG: weak external _foo_default
+; CHECK-DAG: weak private external _foo_hidden
+; CHECK-DAG: weak private external _foo_defined

@llvmorg-github-actions
Copy link
Copy Markdown

@llvm/pr-subscribers-backend-aarch64

Author: syhhyl (syhhyl)

Changes

Mach-O aliases with weak or linkonce linkage were emitted as weak references, which is appropriate for undefined references but not for alias definitions. Emit Mach-O aliases through the same linkage path as other global definitions so weak aliases get .weak_definition.

When writing aliased symbols, keep the aliasee flags and include the alias symbol's own flags so N_WEAK_DEF is preserved in the Mach-O n_desc field.

Fixes #196047


Full diff: https://github.com/llvm/llvm-project/pull/198148.diff

3 Files Affected:

  • (modified) llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp (+3-1)
  • (modified) llvm/lib/MC/MachObjectWriter.cpp (+4-1)
  • (added) llvm/test/CodeGen/AArch64/macho-weak-alias.ll (+17)
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 17fd80e81a673..8c3d69ee43200 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -2640,7 +2640,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 b42155d18bf0a..0786ca0e3a83b 100644
--- a/llvm/lib/MC/MachObjectWriter.cpp
+++ b/llvm/lib/MC/MachObjectWriter.cpp
@@ -443,7 +443,10 @@ 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(EncodeAsAltEntry);
+  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..a936cea618b38
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/macho-weak-alias.ll
@@ -0,0 +1,17 @@
+; RUN: llc -mtriple=aarch64-apple-macosx13.0.0 -filetype=obj %s -o %t.o
+; RUN: llvm-nm -m %t.o | FileCheck %s
+
+define internal void @foo_internal() {
+  ret void
+}
+
+@foo_default = weak_odr alias void (), ptr @foo_internal
+@foo_hidden = weak_odr hidden alias void (), ptr @foo_internal
+
+define weak_odr hidden void @foo_defined() {
+  ret void
+}
+
+; CHECK-DAG: weak external _foo_default
+; CHECK-DAG: weak private external _foo_hidden
+; CHECK-DAG: weak private external _foo_defined

Mach-O aliases with weak or linkonce linkage were emitted as weak references, which is appropriate for undefined references but not for alias definitions. Emit Mach-O aliases through the same linkage path as other global definitions so weak aliases get .weak_definition.

When writing aliased symbols, keep the aliasee flags and include the alias symbol's own flags so N_WEAK_DEF is preserved in the Mach-O n_desc field.

Fixes llvm#196047
@syhhyl syhhyl force-pushed the fix-196047-macho-weak-alias branch from 66f1d94 to 0577ea0 Compare May 17, 2026 07:25
@AsakuraMizu
Copy link
Copy Markdown

This also appears to fix #111321.

@cerisier
Copy link
Copy Markdown
Contributor

cerisier commented Jun 2, 2026

Bumping this for reviewers as this is a quite important fix 🙌

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Mach-O] wrong lowering for alias with weak linkage

3 participants