From 54d05e9077c7b918c5b8414120b1b370bdb34079 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Fri, 31 Jul 2026 19:52:28 -0700 Subject: [PATCH] [SPARC] Parse %r_disp32 in data directives (#213398) commit fd5c1f9497ed (2014) emits %r_disp32 for pc_rel entries in .gcc_except_table and .eh_frame, but the specifier is only recognized in instruction operands, so llvm-mc cannot reassemble llc output. Implement parseDataExpr with a data specifier table holding just %r_disp32, and reject %r_disp32 outside a .word directive and in instruction operands. Supersedes #208933. --- .../Target/Sparc/AsmParser/SparcAsmParser.cpp | 28 +++++++++++++ .../MCTargetDesc/SparcELFObjectWriter.cpp | 17 ++++---- .../Sparc/MCTargetDesc/SparcMCAsmInfo.h | 1 + .../Target/Sparc/MCTargetDesc/SparcMCExpr.cpp | 7 +++- .../Relocations/data-directive-specifier.s | 39 +++++++++++++++++++ 5 files changed, 84 insertions(+), 8 deletions(-) create mode 100644 llvm/test/MC/Sparc/Relocations/data-directive-specifier.s diff --git a/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp b/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp index c6be2489e66a..990a5485943f 100644 --- a/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp +++ b/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp @@ -82,6 +82,8 @@ class SparcAsmParser : public MCTargetAsmParser { bool parseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, OperandVector &Operands) override; ParseStatus parseDirective(AsmToken DirectiveID) override; + bool parseExprWithSpecifier(const MCExpr *&Res, SMLoc &E); + bool parseDataExpr(const MCExpr *&Res) override; unsigned validateTargetOperandClass(MCParsedAsmOperand &Op, unsigned Kind) override; @@ -1768,6 +1770,32 @@ bool SparcAsmParser::matchSparcAsmModifiers(const MCExpr *&EVal, return true; } +bool SparcAsmParser::parseExprWithSpecifier(const MCExpr *&Res, SMLoc &E) { + SMLoc Loc = getLoc(); + if (getLexer().getKind() != AsmToken::Identifier) + return TokError("expected '%' relocation specifier"); + auto Spec = Sparc::parseDataSpecifier(Parser.getTok().getIdentifier()); + if (!Spec) + return TokError("invalid relocation specifier"); + + Parser.Lex(); + if (parseToken(AsmToken::LParen, "expected '('")) + return true; + + const MCExpr *SubExpr; + if (Parser.parseParenExpression(SubExpr, E)) + return true; + Res = MCSpecifierExpr::create(SubExpr, Spec, getContext(), Loc); + return false; +} + +bool SparcAsmParser::parseDataExpr(const MCExpr *&Res) { + SMLoc EndLoc; + if (parseOptionalToken(AsmToken::Percent)) + return parseExprWithSpecifier(Res, EndLoc); + return Parser.parseExpression(Res); +} + bool SparcAsmParser::isPossibleExpression(const AsmToken &Token) { switch (Token.getKind()) { case AsmToken::LParen: diff --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp b/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp index d2071c3e77a5..3b9dbf0261e7 100644 --- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp +++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "MCTargetDesc/SparcFixupKinds.h" +#include "MCTargetDesc/SparcMCAsmInfo.h" #include "MCTargetDesc/SparcMCTargetDesc.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCELFObjectWriter.h" @@ -41,7 +42,9 @@ namespace { unsigned SparcELFObjectWriter::getRelocType(const MCFixup &Fixup, const MCValue &Target, bool IsPCRel) const { - switch (Target.getSpecifier()) { + auto Kind = Fixup.getKind(); + auto Spec = Target.getSpecifier(); + switch (Spec) { case ELF::R_SPARC_TLS_GD_HI22: case ELF::R_SPARC_TLS_GD_LO10: case ELF::R_SPARC_TLS_GD_ADD: @@ -61,21 +64,21 @@ unsigned SparcELFObjectWriter::getRelocType(const MCFixup &Fixup, if (auto *SA = const_cast(Target.getAddSym())) static_cast(SA)->setType(ELF::STT_TLS); break; + case ELF::R_SPARC_DISP32: + if (Kind == FK_Data_4) + return ELF::R_SPARC_DISP32; + reportError(Fixup.getLoc(), "%" + Sparc::getSpecifierName(Spec) + + " can only be used in a .word directive"); + return ELF::R_SPARC_NONE; default: break; } // Extract the relocation type from the fixup kind, after applying STT_TLS as // needed. - auto Kind = Fixup.getKind(); if (mc::isRelocation(Fixup.getKind())) return Kind; - if (const auto *SExpr = dyn_cast(Fixup.getValue())) { - if (SExpr->getSpecifier() == ELF::R_SPARC_DISP32) - return ELF::R_SPARC_DISP32; - } - if (IsPCRel) { switch (Kind) { default: diff --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.h b/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.h index 2afc5dfbe106..7d8a83bfbd5c 100644 --- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.h +++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.h @@ -32,6 +32,7 @@ public: namespace Sparc { uint16_t parseSpecifier(StringRef name); +uint16_t parseDataSpecifier(StringRef name); StringRef getSpecifierName(uint16_t S); } // namespace Sparc diff --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp b/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp index 79da53e1c5bb..0f84fbd702b9 100644 --- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp +++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp @@ -85,7 +85,6 @@ uint16_t Sparc::parseSpecifier(StringRef name) { .Case("got22", ELF::R_SPARC_GOT22) .Case("got10", ELF::R_SPARC_GOT10) .Case("got13", ELF::R_SPARC_GOT13) - .Case("r_disp32", ELF::R_SPARC_DISP32) .Case("tgd_hi22", ELF::R_SPARC_TLS_GD_HI22) .Case("tgd_lo10", ELF::R_SPARC_TLS_GD_LO10) .Case("tgd_add", ELF::R_SPARC_TLS_GD_ADD) @@ -111,3 +110,9 @@ uint16_t Sparc::parseSpecifier(StringRef name) { .Case("gdop", ELF::R_SPARC_GOTDATA_OP) .Default(0); } + +uint16_t Sparc::parseDataSpecifier(StringRef name) { + return StringSwitch(name) + .Case("r_disp32", ELF::R_SPARC_DISP32) + .Default(0); +} diff --git a/llvm/test/MC/Sparc/Relocations/data-directive-specifier.s b/llvm/test/MC/Sparc/Relocations/data-directive-specifier.s new file mode 100644 index 000000000000..f9c01c926c6a --- /dev/null +++ b/llvm/test/MC/Sparc/Relocations/data-directive-specifier.s @@ -0,0 +1,39 @@ +# RUN: llvm-mc -triple=sparc %s | FileCheck %s --check-prefix=ASM +# RUN: llvm-mc -triple=sparc -filetype=obj %s | llvm-readobj -r - | FileCheck %s + +# RUN: not llvm-mc -triple=sparc %s --defsym ERR0=1 2>&1 | FileCheck %s --check-prefix=ERR0 --implicit-check-not=error: +# RUN: not llvm-mc -triple=sparc -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 %r_disp32(l) +# ASM-NEXT: .word %r_disp32(extern+4) +# ASM-NEXT: .word %r_disp32(g+8) + +# CHECK: Section ({{.*}}) .rela.data { +# CHECK-NEXT: 0x0 R_SPARC_DISP32 .text 0x0 +# CHECK-NEXT: 0x4 R_SPARC_DISP32 extern 0x4 +# CHECK-NEXT: 0x8 R_SPARC_DISP32 g 0x8 +# CHECK-NEXT: } +.data +.word %r_disp32(l) +.word %r_disp32(extern + 4), %r_disp32(g + 8) + +.ifdef ERR0 +# ERR0: [[#@LINE+1]]:8: error: invalid relocation specifier +.word %hi(g) + +# ERR0: [[#@LINE+1]]:17: error: expected '(' +.word %r_disp32 g + +# ERR0: [[#@LINE+2]]:8: error: invalid relocation specifier +# ERR0: [[#@LINE+1]]:8: error: unexpected token +sethi %r_disp32(g), %g1 +.endif + +.ifdef ERR +# ERR: [[#@LINE+1]]:8: error: %r_disp32 can only be used in a .word directive +.quad %r_disp32(g) +.endif