[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:
parent
ef19256d33
commit
54d05e9077
5 changed files with 84 additions and 8 deletions
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ public:
|
|||
|
||||
namespace Sparc {
|
||||
uint16_t parseSpecifier(StringRef name);
|
||||
uint16_t parseDataSpecifier(StringRef name);
|
||||
StringRef getSpecifierName(uint16_t S);
|
||||
} // namespace Sparc
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
39
llvm/test/MC/Sparc/Relocations/data-directive-specifier.s
Normal file
39
llvm/test/MC/Sparc/Relocations/data-directive-specifier.s
Normal 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
|
||||
Loading…
Reference in a new issue