[SPARC] Parse %r_disp32 in data directives (#213398)

commit fd5c1f9497 (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.
This commit is contained in:
Fangrui Song 2026-07-31 19:52:28 -07:00 committed by GitHub
parent ef19256d33
commit 54d05e9077
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 84 additions and 8 deletions

View file

@ -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:

View file

@ -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<MCSymbol *>(Target.getAddSym()))
static_cast<MCSymbolELF *>(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<MCSpecifierExpr>(Fixup.getValue())) {
if (SExpr->getSpecifier() == ELF::R_SPARC_DISP32)
return ELF::R_SPARC_DISP32;
}
if (IsPCRel) {
switch (Kind) {
default:

View file

@ -32,6 +32,7 @@ public:
namespace Sparc {
uint16_t parseSpecifier(StringRef name);
uint16_t parseDataSpecifier(StringRef name);
StringRef getSpecifierName(uint16_t S);
} // namespace Sparc

View file

@ -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<uint16_t>(name)
.Case("r_disp32", ELF::R_SPARC_DISP32)
.Default(0);
}

View file

@ -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