Skip to content

AArch64: Replace @plt/%gotpcrel in data directives with %pltpcrel %gotpcrel - #155776

Merged
MaskRay merged 6 commits into
mainfrom
users/MaskRay/spr/aarch64-replace-pltgotpcrel-in-data-directives-with-pltpcrel-gotpcrel-1
Feb 28, 2026
Merged

MaskRay merged 6 commits into
mainfrom
users/MaskRay/spr/aarch64-replace-pltgotpcrel-in-data-directives-with-pltpcrel-gotpcrel-1

Conversation

@MaskRay

@MaskRay MaskRay commented Aug 28, 2025 •

Copy link
Copy Markdown
Member

Similar to #132569 for RISC-V, replace the unofficial @plt and
@gotpcrel relocation specifiers, currently only used by clang
-fexperimental-relative-c++-abi-vtables, with %pltpcrel %gotpcrel. The
syntax is not used in humand-written assembly code, and is not supported
by GNU assembler.

Also replace the recent @funcinit with %funcinit(x).

Created using spr 1.3.5-bogner
@llvmbot

llvmbot commented Aug 28, 2025 •

Copy link
Copy Markdown
Member

@llvm/pr-subscribers-bolt
@llvm/pr-subscribers-backend-aarch64

@llvm/pr-subscribers-lld-elf

Author: Fangrui Song (MaskRay)

Changes

Similar to #132569 for RISC-V, replace the unofficial @<!-- -->plt and
@<!-- -->gotpcrel relocation specifiers, currently only used by clang
-fexperimental-relative-c++-abi-vtables, with %pltpcrel %gotpcrel. The
syntax is not used in humand-written assembly code, and is not supported
by GNU assembler.


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

7 Files Affected:

  • (modified) lld/test/ELF/aarch64-reloc-gotpcrel32.s (+5-5)
  • (modified) lld/test/ELF/aarch64-reloc-plt32.s (+3-3)
  • (modified) llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp (+24)
  • (modified) llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp (+20-5)
  • (modified) llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.cpp (+16-1)
  • (modified) llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.h (+2)
  • (modified) llvm/test/MC/AArch64/data-directive-specifier.s (+37-29)
diff --git a/lld/test/ELF/aarch64-reloc-gotpcrel32.s b/lld/test/ELF/aarch64-reloc-gotpcrel32.s
index 4d007776a86a7..35dfe756f4b24 100644
--- a/lld/test/ELF/aarch64-reloc-gotpcrel32.s
+++ b/lld/test/ELF/aarch64-reloc-gotpcrel32.s
@@ -17,11 +17,11 @@ _start:  // PC = 0x303a0
 // bar@GOTPCREL-4 = 0x20390 (got entry for `bar`) - 0x303a8 (.) - 4 = 0xe4fffeff
 // CHECK:      Contents of section .data:
 // CHECK-NEXT:  {{.*}} f0fffeff f0fffeff e4fffeff
-  .word bar@GOTPCREL
-  .word bar@GOTPCREL+4
-  .word bar@GOTPCREL-4
+  .word %gotpcrel(bar)
+  .word %gotpcrel(bar+4)
+  .word %gotpcrel(bar-4)
 
 // WARN: relocation R_AARCH64_GOTPCREL32 out of range: {{.*}} is not in [-2147483648, 2147483647]; references 'baz'
 // WARN: relocation R_AARCH64_GOTPCREL32 out of range: {{.*}} is not in [-2147483648, 2147483647]; references 'baz'
-  .word baz@GOTPCREL+0xffffffff
-  .word baz@GOTPCREL-0xffffffff
+  .word %gotpcrel(baz+0xffffffff)
+  .word %gotpcrel(baz-0xffffffff)
diff --git a/lld/test/ELF/aarch64-reloc-plt32.s b/lld/test/ELF/aarch64-reloc-plt32.s
index 8a3b989a909b8..cd442e76fcf3d 100644
--- a/lld/test/ELF/aarch64-reloc-plt32.s
+++ b/lld/test/ELF/aarch64-reloc-plt32.s
@@ -32,6 +32,6 @@
   .globl _start
   _start:
 .data
-  .word foo@PLT - . + 2149589079
-  .word foo@PLT - . - 2145378212
-  .word foo@PLT - .
+  .word %pltpcrel(foo + 2149589079)
+  .word %pltpcrel(foo - 2145378212)
+  .word %pltpcrel(foo)
diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
index 3641e22e6f76a..88ccc043d8b89 100644
--- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -181,6 +181,7 @@ class AArch64AsmParser : public MCTargetAsmParser {
   bool showMatchError(SMLoc Loc, unsigned ErrCode, uint64_t ErrorInfo,
                       OperandVector &Operands);
 
+  bool parseExprWithSpecifier(const MCExpr *&Res, SMLoc &E);
   bool parseDataExpr(const MCExpr *&Res) override;
   bool parseAuthExpr(const MCExpr *&Res, SMLoc &EndLoc);
 
@@ -8190,8 +8191,31 @@ bool AArch64AsmParser::parseDirectiveAeabiAArch64Attr(SMLoc L) {
   return false;
 }
 
+bool AArch64AsmParser::parseExprWithSpecifier(const MCExpr *&Res, SMLoc &E) {
+  SMLoc Loc = getLoc();
+  if (getLexer().getKind() != AsmToken::Identifier)
+    return TokError("expected '%' relocation specifier");
+  StringRef Identifier = getParser().getTok().getIdentifier();
+  auto Spec = AArch64::parsePercentSpecifierName(Identifier);
+  if (!Spec)
+    return TokError("invalid relocation specifier");
+
+  getParser().Lex(); // Eat the identifier
+  if (parseToken(AsmToken::LParen, "expected '('"))
+    return true;
+
+  const MCExpr *SubExpr;
+  if (getParser().parseParenExpression(SubExpr, E))
+    return true;
+
+  Res = MCSpecifierExpr::create(SubExpr, Spec, getContext(), Loc);
+  return false;
+}
+
 bool AArch64AsmParser::parseDataExpr(const MCExpr *&Res) {
   SMLoc EndLoc;
+  if (parseOptionalToken(AsmToken::Percent))
+    return parseExprWithSpecifier(Res, EndLoc);
 
   if (getParser().parseExpression(Res))
     return true;
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp
index a388216a95098..5add98dcab931 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp
@@ -104,6 +104,18 @@ unsigned AArch64ELFObjectWriter::getRelocType(const MCFixup &Fixup,
     break;
   }
 
+  switch (RefKind) {
+  case AArch64::S_GOTPCREL:
+  case AArch64::S_PLT:
+    if (Kind == FK_Data_4)
+      break;
+    reportError(Fixup.getLoc(), AArch64::getSpecifierName(RefKind) +
+                                    " can only be used in a .word directive");
+    return ELF::R_RISCV_NONE;
+  default:
+    break;
+  }
+
   // Extract the relocation type from the fixup kind, after applying STT_TLS as
   // needed.
   if (mc::isRelocation(Fixup.getKind()))
@@ -117,8 +129,7 @@ unsigned AArch64ELFObjectWriter::getRelocType(const MCFixup &Fixup,
     case FK_Data_2:
       return R_CLS(PREL16);
     case FK_Data_4: {
-      return Target.getSpecifier() == AArch64::S_PLT ? R_CLS(PLT32)
-                                                     : R_CLS(PREL32);
+      return R_CLS(PREL32);
     }
     case FK_Data_8:
       if (IsILP32) {
@@ -220,9 +231,13 @@ unsigned AArch64ELFObjectWriter::getRelocType(const MCFixup &Fixup,
     case FK_Data_2:
       return R_CLS(ABS16);
     case FK_Data_4:
-      return (!IsILP32 && Target.getSpecifier() == AArch64::S_GOTPCREL)
-                 ? ELF::R_AARCH64_GOTPCREL32
-                 : R_CLS(ABS32);
+      if (!IsILP32) {
+        if (Target.getSpecifier() == AArch64::S_GOTPCREL)
+          return ELF::R_AARCH64_GOTPCREL32;
+        if (Target.getSpecifier() == AArch64::S_PLT)
+          return ELF::R_AARCH64_PLT32;
+      }
+      return R_CLS(ABS32);
     case FK_Data_8: {
       if (IsILP32) {
         reportError(
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.cpp
index 2b5cf3484ffc1..2a3addbc0d71e 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.cpp
@@ -113,12 +113,22 @@ StringRef AArch64::getSpecifierName(AArch64::Specifier S) {
   case AArch64::S_GOT_AUTH:            return ":got_auth:";
   case AArch64::S_GOT_AUTH_PAGE:       return ":got_auth:";
   case AArch64::S_GOT_AUTH_LO12:       return ":got_auth_lo12:";
+
+  case AArch64::S_GOTPCREL:            return "%gotpcrel";
+  case AArch64::S_PLT:                 return "%pltpcrel";
   default:
     llvm_unreachable("Invalid relocation specifier");
   }
   // clang-format on
 }
 
+AArch64::Specifier AArch64::parsePercentSpecifierName(StringRef name) {
+  return StringSwitch<AArch64::Specifier>(name)
+      .Case("pltpcrel", AArch64::S_PLT)
+      .Case("gotpcrel", AArch64::S_GOTPCREL)
+      .Default(0);
+}
+
 static bool evaluate(const MCSpecifierExpr &Expr, MCValue &Res,
                      const MCAssembler *Asm) {
   if (!Expr.getSubExpr()->evaluateAsRelocatable(Res, Asm))
@@ -232,8 +242,13 @@ void AArch64MCAsmInfoELF::printSpecifierExpr(
     raw_ostream &OS, const MCSpecifierExpr &Expr) const {
   if (auto *AE = dyn_cast<AArch64AuthMCExpr>(&Expr))
     return AE->print(OS, this);
-  OS << AArch64::getSpecifierName(Expr.getSpecifier());
+  auto Str = AArch64::getSpecifierName(Expr.getSpecifier());
+  OS << Str;
+  if (!Str.empty() && Str[0] == '%')
+    OS << '(';
   printExpr(OS, *Expr.getSubExpr());
+  if (!Str.empty() && Str[0] == '%')
+    OS << ')';
 }
 
 bool AArch64MCAsmInfoELF::evaluateAsRelocatableImpl(
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.h b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.h
index 0dfa61b1dc60e..971ba58497f96 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.h
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.h
@@ -183,6 +183,8 @@ enum {
 /// (e.g. ":got:", ":lo12:").
 StringRef getSpecifierName(Specifier S);
 
+Specifier parsePercentSpecifierName(StringRef);
+
 inline Specifier getSymbolLoc(Specifier S) {
   return static_cast<Specifier>(S & AArch64::S_SymLocBits);
 }
diff --git a/llvm/test/MC/AArch64/data-directive-specifier.s b/llvm/test/MC/AArch64/data-directive-specifier.s
index 2cb7eb3a3ca81..8d559442ac763 100644
--- a/llvm/test/MC/AArch64/data-directive-specifier.s
+++ b/llvm/test/MC/AArch64/data-directive-specifier.s
@@ -1,54 +1,62 @@
+# RUN: llvm-mc -triple=aarch64 %s | FileCheck %s --check-prefix=ASM
 # RUN: llvm-mc -triple=aarch64 -filetype=obj %s | llvm-readobj -r - | FileCheck %s
-# RUN: not llvm-mc -triple=aarch64 %s --defsym ERR=1 -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR --implicit-check-not=error:
-# RUN: not llvm-mc -triple=aarch64 -filetype=obj %s --defsym OBJERR=1 -o /dev/null 2>&1 | FileCheck %s --check-prefix=OBJERR --implicit-check-not=error:
+
+# RUN: not llvm-mc -triple=aarch64 %s --defsym ERR0=1 2>&1 | FileCheck %s --check-prefix=ERR0 --implicit-check-not=error:
+# RUN: not llvm-mc -triple=aarch64 -filetype=obj %s --defsym ERR=1 -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR --implicit-check-not=error:
 
 .globl g
 g:
 l:
 
+# ASM: .word %pltpcrel(l)
 # CHECK:      Section ({{.*}}) .rela.data {
 # CHECK-NEXT:   0x0 R_AARCH64_PLT32 l 0x0
-# CHECK-NEXT:   0x4 R_AARCH64_PLT32 l 0x4
-# CHECK-NEXT:   0x8 R_AARCH64_PLT32 extern 0x4
-# CHECK-NEXT:   0xC R_AARCH64_PLT32 g 0x8
-# CHECK-NEXT:   0x10 R_AARCH64_PLT32 g 0x18
+# CHECK-NEXT:   0x4 R_AARCH64_PLT32 extern 0x4
+# CHECK-NEXT:   0x8 R_AARCH64_PLT32 g 0x8
 # CHECK-NEXT: }
 .data
-.word l@plt - .
-.word l@plt - .data
-
-.word extern@plt - . + 4
-.word g@plt - . + 8
-.word g@plt - .data + 8
+.word %pltpcrel(l)
+.word %pltpcrel(extern + 4), %pltpcrel(g + 8)
 
+# ASM: .word %gotpcrel(data1)
 # CHECK:      Section ({{.*}}) .rela.data1 {
 # CHECK-NEXT:   0x0 R_AARCH64_GOTPCREL32 data1 0x0
 # CHECK-NEXT:   0x4 R_AARCH64_GOTPCREL32 extern 0x4
-# CHECK-NEXT:    0x8 R_AARCH64_GOTPCREL32 extern 0xFFFFFFFFFFFFFFFB
+# CHECK-NEXT:   0x8 R_AARCH64_GOTPCREL32 extern 0xFFFFFFFFFFFFFFFB
 # CHECK-NEXT: }
 .section .data1,"aw"
 data1:
-.word data1@GOTPCREL
-.word extern@gotpcrel+4
-.word extern@GOTPCREL-5
+.word %gotpcrel(data1)
+.word %gotpcrel(extern+4), %gotpcrel(extern-5)
 
-## Test parse-time errors
-.ifdef ERR
-# ERR: [[#@LINE+1]]:9: error: @ specifier only allowed after a symbol
-.quad 3@plt - .
+.ifdef ERR0
+# ERR0: [[#@LINE+1]]:8: error: invalid relocation specifier
+.word %xxx(l)
+
+# ERR0: [[#@LINE+1]]:17: error: expected '('
+.word %pltpcrel l
 
-# ERR: [[#@LINE+1]]:9: error: expected ')'
-.quad (l@plt - .)
+# ERR0: [[#@LINE+2]]:14: error: unknown token in expression
+# ERR0: [[#@LINE+1]]:14: error: invalid operand
+ldr w0, [x1, %pltpcrel(g)]
 .endif
 
-.ifdef OBJERR
-.quad g@plt - .
+.ifdef ERR
+# ERR: [[#@LINE+1]]:8: error: %pltpcrel can only be used in a .word directive
+.quad %pltpcrel(g)
+
+# ERR: [[#@LINE+1]]:8: error: expected relocatable expression
+.word %pltpcrel(g-.)
+
+# ERR: [[#@LINE+1]]:8: error: expected relocatable expression
+.word %pltpcrel(extern - und)
 
-.word extern@gotpcrel - .
+# ERR: [[#@LINE+1]]:8: error: %gotpcrel can only be used in a .word directive
+.quad %gotpcrel(g)
 
-# OBJERR: [[#@LINE+1]]:7: error: symbol 'und' can not be undefined in a subtraction expression
-.word extern@plt - und
+# ERR: [[#@LINE+1]]:8: error: expected relocatable expression
+.word %gotpcrel(extern - .)
 
-# OBJERR: [[#@LINE+1]]:7: error: symbol 'und' can not be undefined in a subtraction expression
-.word extern@gotpcrel - und
+# ERR: [[#@LINE+1]]:8: error: expected relocatable expression
+.word %gotpcrel(extern - und)
 .endif

Created using spr 1.3.5-bogner

@smithp35 smithp35 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is in line with prior discussions about operators in data directives. These operators (experimental vtable) are also not, yet, implemented in GNU as, so there is freedom to change them in LLVM. One possible typo aside, I think the implementation looks good.

The code in bool AArch64AsmParser::parseDataExpr(const MCExpr *&Res) still has

  } else {
    // Unofficial, experimental syntax that will be changed.
    if (Identifier == "gotpcrel")
      Spec = AArch64::S_GOTPCREL;
    else if (Identifier == "plt")
      Spec = AArch64::S_PLT;
  }

Is it the intention to keep this for now and remove later, or to preserve support for the @ syntax.?

One last check before we commit to this syntax, I got an interesting comment on an ABI PR https://github.com/ARM-software/abi-aa/pull/330/files#r2202065272 where I suggested the use of the %operator() syntax for a TLS debug offset data directive.

IIUC the point in llvm-mc is that having parsed the identifier, the assembler lexes a : which would get stolen from the operator. Looking at the GNU docs https://sourceware.org/binutils/docs/as/Statements.html a space is not permitted before the : so .word : is not a legal label.

I think the code that does this in LLVM is:

  // Check for a label.
  //   ::= identifier ':'
  //   ::= number ':'
  if (Lexer.is(AsmToken::Colon) && getTargetParser().isLabel(ID)) {
    if (checkForValidSection())
      return true;

    Lex(); // Consume the ':'.

If I've understood the ABI comment then it could be possible to do something like (pseudo code)

If previous identifier a data directive and next token an operator then do not consider the `:` as part of a label.

That would permit a .word :pltpcrel: foo + 2149589079 to avoid having separate code and data operators.

To get an answer to the ABI comment. Would it be too difficult or messy in both LLVM and GAS to implement something like this?

Comment thread llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp Outdated
Created using spr 1.3.5-bogner

@smithp35 smithp35 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code changes look good to me. I've got one question about the naming in the interface.

Outside the scope of this patch I'm thinking of how best to document these. The sysvabi64 is probably the best place https://github.com/ARM-software/abi-aa/blob/main/sysvabi64/sysvabi64.rst#65assembler-language-addressing-mode-conventions-for-data although these operators don't require sysv.

switch (RefKind) {
case AArch64::S_GOTPCREL:
case AArch64::S_PLT:
if (Kind == FK_Data_4)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking of the interface here. We could have a fixed interface like this where %pltpcrel could only apply to .word and only produce a ELF::R_AARCH64_PLT32 reloc. Or we could have an interface that changes the reloc when a different size directive is used. For example .xword could produce a theoretical ELF::R_AARCH64_PLT64 reloc.

If it is the former I think we would be best putting 4 in the name of the expression such as %pltpcrel4 so that we could introduce %pltpcrel8 later.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While we currently support .long %pltpcrel(x), we can extend this to .quad %pltpcrel(x) if we intend to add R_AARCH64_PLT64. I'd prefer %pltpcrel to a name that explicitly encodes the width.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. I think the relocation type is (or would be obvious) from the directive size.

Would you be able to add a comment above the reportError, something like:

Only R_AARCH64_PLT32 defined at present, can be extended to other directives if additional relocations are defined.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the suggestion. Added comment

@smithp35 smithp35 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One final comment suggestion from me.

It would be good to give those that introduced the directive a heads up that the syntax is changing. I don't think anyone is hand-rolling relative vtables in assembly, but if they are they'll need to update their code.

switch (RefKind) {
case AArch64::S_GOTPCREL:
case AArch64::S_PLT:
if (Kind == FK_Data_4)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. I think the relocation type is (or would be obvious) from the directive size.

Would you be able to add a comment above the reportError, something like:

Only R_AARCH64_PLT32 defined at present, can be extended to other directives if additional relocations are defined.

@MaskRay

MaskRay commented Feb 27, 2026

Copy link
Copy Markdown
Member Author

@PiJoules for R_AARCH64_PLT32 R_AARCH64_GOTPCREL32

Created using spr 1.3.5-bogner
Created using spr 1.3.5-bogner
@PiJoules

Copy link
Copy Markdown
Contributor

LGTM assuming this is purely syntactic and doesn't change the behavior of the actual relocs. AFAICT no one's been using the old syntax outside of tests but if anyone is then I think this PR provides enough examples for how to update the syntax.

@github-actions

Copy link
Copy Markdown

🐧 Linux x64 Test Results

  • 170219 tests passed
  • 3085 tests skipped
  • 1 test failed

Failed Tests

(click on a test name to see its output)

BOLT

BOLT.AArch64/skip-non-vfuncptr-reloc-in-relative-vtable.s
Exit Code: 1

Command Output (stdout):
--
# RUN: at line 4
/home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/llvm-mc -filetype=obj -triple aarch64-unknown-gnu /home/gha/actions-runner/_work/llvm-project/llvm-project/bolt/test/AArch64/skip-non-vfuncptr-reloc-in-relative-vtable.s -o /home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/bolt/test/AArch64/Output/skip-non-vfuncptr-reloc-in-relative-vtable.s.tmp.o
# executed command: /home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/llvm-mc -filetype=obj -triple aarch64-unknown-gnu /home/gha/actions-runner/_work/llvm-project/llvm-project/bolt/test/AArch64/skip-non-vfuncptr-reloc-in-relative-vtable.s -o /home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/bolt/test/AArch64/Output/skip-non-vfuncptr-reloc-in-relative-vtable.s.tmp.o
# .---command stderr------------
# | /home/gha/actions-runner/_work/llvm-project/llvm-project/bolt/test/AArch64/skip-non-vfuncptr-reloc-in-relative-vtable.s:34:12: error: invalid relocation specifier
# |         .word   foo@PLT-_ZTV3gooE-8
# |                     ^
# `-----------------------------
# error: command failed with exit status: 1

--

If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the infrastructure label.

Created using spr 1.3.5-bogner
@MaskRay
MaskRay enabled auto-merge (squash) February 28, 2026 05:03
@MaskRay
MaskRay merged commit bed8997 into main Feb 28, 2026
10 of 11 checks passed
@MaskRay
MaskRay deleted the users/MaskRay/spr/aarch64-replace-pltgotpcrel-in-data-directives-with-pltpcrel-gotpcrel-1 branch February 28, 2026 05:38
@gulfemsavrun

Copy link
Copy Markdown
Contributor

We started seeing a lld relocation issue when linking libc++, and I bisected it to this commit:

[2416/2458](3) Linking CXX shared library /b/s/w/ir/x/w/llvm_build/lib/aarch64-unknown-fuchsia/libc++abi.so.1.0
FAILED: /b/s/w/ir/x/w/llvm_build/lib/aarch64-unknown-fuchsia/libc++abi.so.1.0 
: && /b/s/w/ir/x/w/llvm_build/./bin/clang++ --target=aarch64-unknown-fuchsia --sysroot=/b/s/w/ir/x/w/sdk/arch/arm64/sysroot -fPIC --target=aarch64-unknown-fuchsia -I/b/s/w/ir/x/w/sdk/pkg/sync/include -I/b/s/w/ir/x/w/sdk/pkg/fdio/include -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wno-pass-failed -Wmisleading-indentation -Wctad-maybe-unsupported -ffunction-sections -fdata-sections -Xclang -fno-pch-timestamp -ffile-prefix-map=/b/s/w/ir/x/w/llvm_build/runtimes/runtimes-aarch64-unknown-fuchsia-bins=../../../llvm-llvm-project -ffile-prefix-map=/b/s/w/ir/x/w/llvm-llvm-project/= -no-canonical-prefixes  -O2 -g -DNDEBUG  -L/b/s/w/ir/x/w/sdk/arch/arm64/lib -Wl,-z,defs -fuse-ld=lld  -Wl,--push-state,--as-needed,-lzircon,--pop-state -nostdlib++ --unwindlib=none -shared -Wl,-soname,libc++abi.so.1 -o /b/s/w/ir/x/w/llvm_build/lib/aarch64-unknown-fuchsia/libc++abi.so.1.0 libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/cxa_aux_runtime.cpp.obj libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/cxa_default_handlers.cpp.obj libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/cxa_demangle.cpp.obj libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/cxa_exception_storage.cpp.obj libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/cxa_guard.cpp.obj libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/cxa_handlers.cpp.obj libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/cxa_vector.cpp.obj libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/cxa_virtual.cpp.obj libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/stdlib_exception.cpp.obj libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/stdlib_stdexcept.cpp.obj libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/stdlib_typeinfo.cpp.obj libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/abort_message.cpp.obj libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/fallback_malloc.cpp.obj libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/private_typeinfo.cpp.obj libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/stdlib_new_delete.cpp.obj libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/cxa_exception.cpp.obj libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/cxa_personality.cpp.obj libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/cxa_thread_atexit.cpp.obj  -lc  /b/s/w/ir/x/w/llvm_build/lib/aarch64-unknown-fuchsia/libunwind.so.1.0 && :
ld.lld: error: relocation R_AARCH64_PREL32 cannot be used against symbol 'std::bad_cast::~bad_cast()'; recompile with -fPIC
>>> defined in libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/stdlib_typeinfo.cpp.obj
>>> referenced by stdlib_typeinfo.cpp
>>>               libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/stdlib_typeinfo.cpp.obj:(vtable for std::bad_cast (.local))

ld.lld: error: relocation R_AARCH64_PREL32 cannot be used against symbol 'std::bad_cast::~bad_cast()'; recompile with -fPIC
>>> defined in libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/stdlib_typeinfo.cpp.obj
>>> referenced by stdlib_typeinfo.cpp

https://luci-milo.appspot.com/ui/p/fuchsia/builders/toolchain.ci/clang-linux-x64/b8688417347456898897/overview

@frobtech

frobtech commented Mar 2, 2026

Copy link
Copy Markdown
Contributor

The failure mode suggests that the reference in the vtable accidentally got changed from referring to the local alias to referring to the public symbol.

@frobtech

frobtech commented Mar 2, 2026

Copy link
Copy Markdown
Contributor

The failure mode suggests that the reference in the vtable accidentally got changed from referring to the local alias to referring to the public symbol.

Oh, actually, it may more likely be that a PLT32 case got changed to PREL32 accidentally. Some changes in llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp seem like a good suspect.

case FK_Data_2:
return R_CLS(PREL16);
case FK_Data_4: {
return Target.getSpecifier() == AArch64::S_PLT ? R_CLS(PLT32)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PLT32 was previously emitted here

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missed this on review. This is leading to the link issue we see at https://luci-milo.appspot.com/ui/p/fuchsia/builders/toolchain.ci/clang-linux-x64/b8688417347456898897/overview

[2416/2458](3) Linking CXX shared library /b/s/w/ir/x/w/llvm_build/lib/aarch64-unknown-fuchsia/libc++abi.so.1.0
FAILED: /b/s/w/ir/x/w/llvm_build/lib/aarch64-unknown-fuchsia/libc++abi.so.1.0 
: && /b/s/w/ir/x/w/llvm_build/./bin/clang++ --target=aarch64-unknown-fuchsia --sysroot=/b/s/w/ir/x/w/sdk/arch/arm64/sysroot -fPIC --target=aarch64-unknown-fuchsia -I/b/s/w/ir/x/w/sdk/pkg/sync/include -I/b/s/w/ir/x/w/sdk/pkg/fdio/include -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wno-pass-failed -Wmisleading-indentation -Wctad-maybe-unsupported -ffunction-sections -fdata-sections -Xclang -fno-pch-timestamp -ffile-prefix-map=/b/s/w/ir/x/w/llvm_build/runtimes/runtimes-aarch64-unknown-fuchsia-bins=../../../llvm-llvm-project -ffile-prefix-map=/b/s/w/ir/x/w/llvm-llvm-project/= -no-canonical-prefixes  -O2 -g -DNDEBUG  -L/b/s/w/ir/x/w/sdk/arch/arm64/lib -Wl,-z,defs -fuse-ld=lld  -Wl,--push-state,--as-needed,-lzircon,--pop-state -nostdlib++ --unwindlib=none -shared -Wl,-soname,libc++abi.so.1 -o /b/s/w/ir/x/w/llvm_build/lib/aarch64-unknown-fuchsia/libc++abi.so.1.0 libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/cxa_aux_runtime.cpp.obj libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/cxa_default_handlers.cpp.obj libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/cxa_demangle.cpp.obj libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/cxa_exception_storage.cpp.obj libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/cxa_guard.cpp.obj libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/cxa_handlers.cpp.obj libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/cxa_vector.cpp.obj libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/cxa_virtual.cpp.obj libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/stdlib_exception.cpp.obj libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/stdlib_stdexcept.cpp.obj libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/stdlib_typeinfo.cpp.obj libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/abort_message.cpp.obj libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/fallback_malloc.cpp.obj libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/private_typeinfo.cpp.obj libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/stdlib_new_delete.cpp.obj libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/cxa_exception.cpp.obj libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/cxa_personality.cpp.obj libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/cxa_thread_atexit.cpp.obj  -lc  /b/s/w/ir/x/w/llvm_build/lib/aarch64-unknown-fuchsia/libunwind.so.1.0 && :
ld.lld: error: relocation R_AARCH64_PREL32 cannot be used against symbol 'std::bad_cast::~bad_cast()'; recompile with -fPIC
>>> defined in libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/stdlib_typeinfo.cpp.obj
>>> referenced by stdlib_typeinfo.cpp
>>>               libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/stdlib_typeinfo.cpp.obj:(vtable for std::bad_cast (.local))

ld.lld: error: relocation R_AARCH64_PREL32 cannot be used against symbol 'std::bad_cast::~bad_cast()'; recompile with -fPIC
>>> defined in libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/stdlib_typeinfo.cpp.obj
>>> referenced by stdlib_typeinfo.cpp
>>>               libcxxabi/src/CMakeFiles/cxxabi_shared_objects.dir/stdlib_typeinfo.cpp.obj:(vtable for std::bad_cast (.local))

so I think this part should remain untouched.

if (Target.getSpecifier() == AArch64::S_GOTPCREL)
return ELF::R_AARCH64_GOTPCREL32;
if (Target.getSpecifier() == AArch64::S_PLT)
return ELF::R_AARCH64_PLT32;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But now emitted here?

MaskRay added a commit to MaskRay/llvm-project that referenced this pull request Mar 3, 2026
…ierExpr

PR llvm#155776 changed S_PLT/S_GOTPCREL printing to %pltpcrel(x)/%gotpcrel(x)
syntax via MCSpecifierExpr, but lowerSymbolDifference and
getIndirectSymViaGOTPCRel still created MCSymbolRefExpr with these
specifiers, which prints via the @-specifier table as @PLT/@GOTPCREL,
leading to incorrect relocation types.

Fixes: bed8997
(AArch64: Replace @plt/%gotpcrel in data directives with %pltpcrel %gotpcrel (llvm#155776))

Add llvm/test/CodeGen/AArch64/dso_local_equivalent.ll
@MaskRay

MaskRay commented Mar 3, 2026

Copy link
Copy Markdown
Member Author

Sorry for the --target=aarch64 -fexperimental-relative-c++-abi-vtables regression. AArch64 does not have test coverage for this mode - while RISC-V has llvm/test/CodeGen/RISCV/dso_local_equivalent.ll. Fixing this in #184393

MaskRay added a commit that referenced this pull request Mar 3, 2026
…ierExpr (#184393)

PR #155776 changed S_PLT/S_GOTPCREL printing to
%pltpcrel(x)/%gotpcrel(x)
syntax via MCSpecifierExpr, but lowerSymbolDifference and
getIndirectSymViaGOTPCRel still created MCSymbolRefExpr with these
specifiers, which prints via the @-specifier table as @PLT/@GOTPCREL,
leading to incorrect relocation types.

Fixes: bed8997
(AArch64: Replace @plt/%gotpcrel in data directives with %pltpcrel
%gotpcrel (#155776))

Add llvm/test/CodeGen/AArch64/dso_local_equivalent.ll
gulfemsavrun added a commit to gulfemsavrun/llvm-project that referenced this pull request Mar 3, 2026
…MCSpecifierExpr (llvm#184393)"

This reverts commit a34d56d.

Revert "AArch64: Replace @plt/%gotpcrel in data directives with %pltpcrel %gotpcrel (llvm#155776)"

This reverts commit bed8997.
sahas3 pushed a commit to sahas3/llvm-project that referenced this pull request Mar 4, 2026
…tpcrel (llvm#155776)

Similar to llvm#132569 for RISC-V, replace the unofficial `@plt` and
`@gotpcrel` relocation specifiers, currently only used by clang
-fexperimental-relative-c++-abi-vtables, with %pltpcrel %gotpcrel. The
syntax is not used in humand-written assembly code, and is not supported
by GNU assembler.

Also replace the recent `@funcinit` with `%funcinit(x)`.
sahas3 pushed a commit to sahas3/llvm-project that referenced this pull request Mar 4, 2026
…ierExpr (llvm#184393)

PR llvm#155776 changed S_PLT/S_GOTPCREL printing to
%pltpcrel(x)/%gotpcrel(x)
syntax via MCSpecifierExpr, but lowerSymbolDifference and
getIndirectSymViaGOTPCRel still created MCSymbolRefExpr with these
specifiers, which prints via the @-specifier table as @PLT/@GOTPCREL,
leading to incorrect relocation types.

Fixes: bed8997
(AArch64: Replace @plt/%gotpcrel in data directives with %pltpcrel
%gotpcrel (llvm#155776))

Add llvm/test/CodeGen/AArch64/dso_local_equivalent.ll
sujianIBM pushed a commit to sujianIBM/llvm-project that referenced this pull request Mar 5, 2026
…tpcrel (llvm#155776)

Similar to llvm#132569 for RISC-V, replace the unofficial `@plt` and
`@gotpcrel` relocation specifiers, currently only used by clang
-fexperimental-relative-c++-abi-vtables, with %pltpcrel %gotpcrel. The
syntax is not used in humand-written assembly code, and is not supported
by GNU assembler.

Also replace the recent `@funcinit` with `%funcinit(x)`.
sujianIBM pushed a commit to sujianIBM/llvm-project that referenced this pull request Mar 5, 2026
…ierExpr (llvm#184393)

PR llvm#155776 changed S_PLT/S_GOTPCREL printing to
%pltpcrel(x)/%gotpcrel(x)
syntax via MCSpecifierExpr, but lowerSymbolDifference and
getIndirectSymViaGOTPCRel still created MCSymbolRefExpr with these
specifiers, which prints via the @-specifier table as @PLT/@GOTPCREL,
leading to incorrect relocation types.

Fixes: bed8997
(AArch64: Replace @plt/%gotpcrel in data directives with %pltpcrel
%gotpcrel (llvm#155776))

Add llvm/test/CodeGen/AArch64/dso_local_equivalent.ll
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants