From 7056b689702bdd6c5bb8508be8fbff707cf250e5 Mon Sep 17 00:00:00 2001 From: Daniel Sanders Date: Thu, 12 Nov 2015 13:33:00 +0000 Subject: [PATCH] Implement .reloc (constant offset only) with support for R_MIPS_NONE and R_MIPS_32. Summary: Support for R_MIPS_NONE allows us to parse MIPS16's usage of .reloc. R_MIPS_32 was included to be able to better test the directive. Targets can add their relocations by overriding MCAsmBackend::getFixupKind(). Subscribers: grosbach, rafael, majnemer, dsanders, llvm-commits Differential Revision: http://reviews.llvm.org/D13659 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@252888 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/MC/MCAsmBackend.h | 5 ++ include/llvm/MC/MCObjectStreamer.h | 2 + include/llvm/MC/MCStreamer.h | 8 +++ lib/MC/MCAsmBackend.cpp | 4 ++ lib/MC/MCAsmStreamer.cpp | 16 +++++ lib/MC/MCObjectStreamer.cpp | 20 +++++++ lib/MC/MCParser/AsmParser.cpp | 51 ++++++++++++++++ .../Mips/MCTargetDesc/MipsAsmBackend.cpp | 14 +++++ lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h | 1 + .../Mips/MCTargetDesc/MipsELFObjectWriter.cpp | 2 + lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h | 5 +- test/MC/Mips/reloc-directive-bad.s | 6 ++ test/MC/Mips/reloc-directive.s | 58 +++++++++++++++++++ 13 files changed, 191 insertions(+), 1 deletion(-) create mode 100644 test/MC/Mips/reloc-directive-bad.s create mode 100644 test/MC/Mips/reloc-directive.s diff --git a/include/llvm/MC/MCAsmBackend.h b/include/llvm/MC/MCAsmBackend.h index 2bfad2d355b..51312ff8044 100644 --- a/include/llvm/MC/MCAsmBackend.h +++ b/include/llvm/MC/MCAsmBackend.h @@ -67,6 +67,11 @@ public: /// Get the number of target specific fixup kinds. virtual unsigned getNumFixupKinds() const = 0; + /// Map a relocation name used in .reloc to a fixup kind. + /// Returns true and sets MappedKind if Name is successfully mapped. + /// Otherwise returns false and leaves MappedKind unchanged. + virtual bool getFixupKind(StringRef Name, MCFixupKind &MappedKind) const; + /// Get information on a fixup kind. virtual const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const; diff --git a/include/llvm/MC/MCObjectStreamer.h b/include/llvm/MC/MCObjectStreamer.h index 3de44f8e789..9fe2fda2135 100644 --- a/include/llvm/MC/MCObjectStreamer.h +++ b/include/llvm/MC/MCObjectStreamer.h @@ -124,6 +124,8 @@ public: const MCSymbol *Label); void EmitGPRel32Value(const MCExpr *Value) override; void EmitGPRel64Value(const MCExpr *Value) override; + bool EmitRelocDirective(const MCExpr &Offset, StringRef Name, + const MCExpr *Expr, SMLoc Loc) override; void EmitFill(uint64_t NumBytes, uint8_t FillValue) override; void FinishImpl() override; diff --git a/include/llvm/MC/MCStreamer.h b/include/llvm/MC/MCStreamer.h index 67e24420113..02b9d18af5f 100644 --- a/include/llvm/MC/MCStreamer.h +++ b/include/llvm/MC/MCStreamer.h @@ -682,6 +682,14 @@ public: virtual void EmitSyntaxDirective(); + /// \brief Emit a .reloc directive. + /// Returns true if the relocation could not be emitted because Name is not + /// known. + virtual bool EmitRelocDirective(const MCExpr &Offset, StringRef Name, + const MCExpr *Expr, SMLoc Loc) { + return true; + } + /// \brief Emit the given \p Instruction into the current section. virtual void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI); diff --git a/lib/MC/MCAsmBackend.cpp b/lib/MC/MCAsmBackend.cpp index 36c65b7bcd4..fcf139b7253 100644 --- a/lib/MC/MCAsmBackend.cpp +++ b/lib/MC/MCAsmBackend.cpp @@ -16,6 +16,10 @@ MCAsmBackend::MCAsmBackend() : HasDataInCodeSupport(false) {} MCAsmBackend::~MCAsmBackend() {} +bool MCAsmBackend::getFixupKind(StringRef Name, MCFixupKind &MappedKind) const { + return false; +} + const MCFixupKindInfo &MCAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { static const MCFixupKindInfo Builtins[] = { {"FK_Data_1", 0, 8, 0}, diff --git a/lib/MC/MCAsmStreamer.cpp b/lib/MC/MCAsmStreamer.cpp index 4f2d1d2229d..c99ce7752b3 100644 --- a/lib/MC/MCAsmStreamer.cpp +++ b/lib/MC/MCAsmStreamer.cpp @@ -240,6 +240,9 @@ public: void EmitBundleLock(bool AlignToEnd) override; void EmitBundleUnlock() override; + bool EmitRelocDirective(const MCExpr &Offset, StringRef Name, + const MCExpr *Expr, SMLoc Loc) override; + /// EmitRawText - If this file is backed by an assembly streamer, this dumps /// the specified string in the output .s file. This capability is /// indicated by the hasRawTextSupport() predicate. @@ -1357,6 +1360,19 @@ void MCAsmStreamer::EmitBundleUnlock() { EmitEOL(); } +bool MCAsmStreamer::EmitRelocDirective(const MCExpr &Offset, StringRef Name, + const MCExpr *Expr, SMLoc) { + OS << "\t.reloc "; + Offset.print(OS, MAI); + OS << ", " << Name; + if (Expr) { + OS << ", "; + Expr->print(OS, MAI); + } + EmitEOL(); + return false; +} + /// EmitRawText - If this file is backed by an assembly streamer, this dumps /// the specified string in the output .s file. This capability is /// indicated by the hasRawTextSupport() predicate. diff --git a/lib/MC/MCObjectStreamer.cpp b/lib/MC/MCObjectStreamer.cpp index c47e2162b63..d0a7dafa15b 100644 --- a/lib/MC/MCObjectStreamer.cpp +++ b/lib/MC/MCObjectStreamer.cpp @@ -416,6 +416,26 @@ void MCObjectStreamer::EmitGPRel64Value(const MCExpr *Value) { DF->getContents().resize(DF->getContents().size() + 8, 0); } +bool MCObjectStreamer::EmitRelocDirective(const MCExpr &Offset, StringRef Name, + const MCExpr *Expr, SMLoc Loc) { + int64_t OffsetValue; + if (!Offset.evaluateAsAbsolute(OffsetValue)) + llvm_unreachable("Offset is not absolute"); + + MCDataFragment *DF = getOrCreateDataFragment(); + flushPendingLabels(DF, DF->getContents().size()); + + MCFixupKind Kind; + if (!Assembler->getBackend().getFixupKind(Name, Kind)) + return true; + + if (Expr == nullptr) + Expr = + MCSymbolRefExpr::create(getContext().createTempSymbol(), getContext()); + DF->getFixups().push_back(MCFixup::create(OffsetValue, Expr, Kind, Loc)); + return false; +} + void MCObjectStreamer::EmitFill(uint64_t NumBytes, uint8_t FillValue) { const MCSection *Sec = getCurrentSection().first; assert(Sec && "need a section"); diff --git a/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp index 245ba44a249..dd0e6bde9d8 100644 --- a/lib/MC/MCParser/AsmParser.cpp +++ b/lib/MC/MCParser/AsmParser.cpp @@ -33,6 +33,7 @@ #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCTargetAsmParser.h" +#include "llvm/MC/MCValue.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" @@ -342,6 +343,7 @@ private: enum DirectiveKind { DK_NO_DIRECTIVE, // Placeholder DK_SET, DK_EQU, DK_EQUIV, DK_ASCII, DK_ASCIZ, DK_STRING, DK_BYTE, DK_SHORT, + DK_RELOC, DK_VALUE, DK_2BYTE, DK_LONG, DK_INT, DK_4BYTE, DK_QUAD, DK_8BYTE, DK_OCTA, DK_SINGLE, DK_FLOAT, DK_DOUBLE, DK_ALIGN, DK_ALIGN32, DK_BALIGN, DK_BALIGNW, DK_BALIGNL, DK_P2ALIGN, DK_P2ALIGNW, DK_P2ALIGNL, DK_ORG, DK_FILL, DK_ENDR, @@ -374,6 +376,7 @@ private: // ".ascii", ".asciz", ".string" bool parseDirectiveAscii(StringRef IDVal, bool ZeroTerminated); + bool parseDirectiveReloc(SMLoc DirectiveLoc); // ".reloc" bool parseDirectiveValue(unsigned Size); // ".byte", ".long", ... bool parseDirectiveOctaValue(); // ".octa" bool parseDirectiveRealValue(const fltSemantics &); // ".single", ... @@ -1695,6 +1698,8 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, return parseDirectiveError(IDLoc, true); case DK_WARNING: return parseDirectiveWarning(IDLoc); + case DK_RELOC: + return parseDirectiveReloc(IDLoc); } return Error(IDLoc, "unknown directive"); @@ -2463,6 +2468,51 @@ bool AsmParser::parseDirectiveAscii(StringRef IDVal, bool ZeroTerminated) { return false; } +/// parseDirectiveReloc +/// ::= .reloc expression , identifier [ , expression ] +bool AsmParser::parseDirectiveReloc(SMLoc DirectiveLoc) { + const MCExpr *Offset; + const MCExpr *Expr = nullptr; + + SMLoc OffsetLoc = Lexer.getTok().getLoc(); + if (parseExpression(Offset)) + return true; + + // We can only deal with constant expressions at the moment. + int64_t OffsetValue; + if (!Offset->evaluateAsAbsolute(OffsetValue)) + return Error(OffsetLoc, "expression is not a constant value"); + + if (Lexer.isNot(AsmToken::Comma)) + return TokError("expected comma"); + Lexer.Lex(); + + if (Lexer.isNot(AsmToken::Identifier)) + return TokError("expected relocation name"); + SMLoc NameLoc = Lexer.getTok().getLoc(); + StringRef Name = Lexer.getTok().getIdentifier(); + Lexer.Lex(); + + if (Lexer.is(AsmToken::Comma)) { + Lexer.Lex(); + SMLoc ExprLoc = Lexer.getLoc(); + if (parseExpression(Expr)) + return true; + + MCValue Value; + if (!Expr->evaluateAsRelocatable(Value, nullptr, nullptr)) + return Error(ExprLoc, "expression must be relocatable"); + } + + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in .reloc directive"); + + if (getStreamer().EmitRelocDirective(*Offset, Name, Expr, DirectiveLoc)) + return Error(NameLoc, "unknown relocation name"); + + return false; +} + /// parseDirectiveValue /// ::= (.byte | .short | ... ) [ expression (, expression)* ] bool AsmParser::parseDirectiveValue(unsigned Size) { @@ -4358,6 +4408,7 @@ void AsmParser::initializeDirectiveKindMap() { DirectiveKindMap[".err"] = DK_ERR; DirectiveKindMap[".error"] = DK_ERROR; DirectiveKindMap[".warning"] = DK_WARNING; + DirectiveKindMap[".reloc"] = DK_RELOC; } MCAsmMacro *AsmParser::parseMacroLikeBody(SMLoc DirectiveLoc) { diff --git a/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp b/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp index da16bebba36..a9b31ac877d 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp +++ b/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp @@ -232,6 +232,18 @@ void MipsAsmBackend::applyFixup(const MCFixup &Fixup, char *Data, } } +bool MipsAsmBackend::getFixupKind(StringRef Name, MCFixupKind &MappedKind) const { + if (Name == "R_MIPS_NONE") { + MappedKind = (MCFixupKind)Mips::fixup_Mips_NONE; + return true; + } + if (Name == "R_MIPS_32") { + MappedKind = FK_Data_4; + return true; + } + return MCAsmBackend::getFixupKind(Name, MappedKind); +} + const MCFixupKindInfo &MipsAsmBackend:: getFixupKindInfo(MCFixupKind Kind) const { const static MCFixupKindInfo LittleEndianInfos[Mips::NumTargetFixupKinds] = { @@ -239,6 +251,7 @@ getFixupKindInfo(MCFixupKind Kind) const { // MipsFixupKinds.h. // // name offset bits flags + { "fixup_Mips_NONE", 0, 0, 0 }, { "fixup_Mips_16", 0, 16, 0 }, { "fixup_Mips_32", 0, 32, 0 }, { "fixup_Mips_REL32", 0, 32, 0 }, @@ -304,6 +317,7 @@ getFixupKindInfo(MCFixupKind Kind) const { // MipsFixupKinds.h. // // name offset bits flags + { "fixup_Mips_NONE", 0, 0, 0 }, { "fixup_Mips_16", 16, 16, 0 }, { "fixup_Mips_32", 0, 32, 0 }, { "fixup_Mips_REL32", 0, 32, 0 }, diff --git a/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h b/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h index b3d5a4964f8..1c9af9227ff 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h +++ b/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h @@ -41,6 +41,7 @@ public: void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, uint64_t Value, bool IsPCRel) const override; + bool getFixupKind(StringRef Name, MCFixupKind &MappedKind) const override; const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override; unsigned getNumFixupKinds() const override { diff --git a/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp b/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp index 9b2952720ed..864188670a9 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp +++ b/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp @@ -68,6 +68,8 @@ unsigned MipsELFObjectWriter::GetRelocType(const MCValue &Target, unsigned Kind = (unsigned)Fixup.getKind(); switch (Kind) { + case Mips::fixup_Mips_NONE: + return ELF::R_MIPS_NONE; case Mips::fixup_Mips_16: case FK_Data_2: return IsPCRel ? ELF::R_MIPS_PC16 : ELF::R_MIPS_16; diff --git a/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h b/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h index e601963264d..3652f4bab0d 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h +++ b/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h @@ -23,8 +23,11 @@ namespace Mips { // in MipsAsmBackend.cpp. // enum Fixups { + // Branch fixups resulting in R_MIPS_NONE. + fixup_Mips_NONE = FirstTargetFixupKind, + // Branch fixups resulting in R_MIPS_16. - fixup_Mips_16 = FirstTargetFixupKind, + fixup_Mips_16, // Pure 32 bit data fixup resulting in - R_MIPS_32. fixup_Mips_32, diff --git a/test/MC/Mips/reloc-directive-bad.s b/test/MC/Mips/reloc-directive-bad.s new file mode 100644 index 00000000000..41f21ed36de --- /dev/null +++ b/test/MC/Mips/reloc-directive-bad.s @@ -0,0 +1,6 @@ +# RUN: not llvm-mc -triple mips-unknown-linux < %s -show-encoding -target-abi=o32 \ +# RUN: 2>&1 | FileCheck %s + .text +foo: + .reloc 0, R_MIPS_32, .text+.text # CHECK: :[[@LINE]]:23: error: expression must be relocatable + nop diff --git a/test/MC/Mips/reloc-directive.s b/test/MC/Mips/reloc-directive.s new file mode 100644 index 00000000000..f42a1bc699f --- /dev/null +++ b/test/MC/Mips/reloc-directive.s @@ -0,0 +1,58 @@ +# RUN: llvm-mc -triple mips-unknown-linux < %s -show-encoding -target-abi=o32 \ +# RUN: | FileCheck -check-prefix=ASM %s +# RUN: llvm-mc -triple mips64-unknown-linux < %s -show-encoding -target-abi=n32 \ +# RUN: | FileCheck -check-prefix=ASM %s +# RUN: llvm-mc -triple mips64-unknown-linux < %s -show-encoding -target-abi=n64 \ +# RUN: | FileCheck -check-prefix=ASM %s +# RUN: llvm-mc -triple mips-unknown-linux < %s -show-encoding -target-abi=o32 \ +# RUN: -filetype=obj | llvm-readobj -sections -section-data -r | \ +# RUN: FileCheck -check-prefix=OBJ-O32 %s +# RUN: llvm-mc -triple mips64-unknown-linux < %s -show-encoding -target-abi=n32 \ +# RUN: -filetype=obj | llvm-readobj -sections -section-data -r | \ +# RUN: FileCheck -check-prefix=OBJ-N32 %s +# RUN: llvm-mc -triple mips64-unknown-linux < %s -show-encoding -target-abi=n64 \ +# RUN: -filetype=obj | llvm-readobj -sections -section-data -r | \ +# RUN: FileCheck -check-prefix=OBJ-N64 %s + .text +foo: + .reloc 4, R_MIPS_NONE, foo # ASM: .reloc 4, R_MIPS_NONE, foo + .reloc 0, R_MIPS_NONE, foo+4 # ASM: .reloc 0, R_MIPS_NONE, foo+4 + .reloc 8, R_MIPS_32, foo+8 # ASM: .reloc 8, R_MIPS_32, foo+8 + nop + nop + nop + .reloc 12, R_MIPS_NONE # ASM: .reloc 12, R_MIPS_NONE{{$}} + nop + +# OBJ-O32-LABEL: Name: .text +# OBJ-O32: 0000: 00000000 00000000 00000008 +# OBJ-O32-LABEL: } +# OBJ-O32-LABEL: Relocations [ +# OBJ-O32: 0x0 R_MIPS_NONE foo 0x0 +# OBJ-O32: 0x4 R_MIPS_NONE foo 0x0 +# OBJ-O32: 0x8 R_MIPS_32 .text 0x0 +# OBJ-O32: 0xC R_MIPS_NONE - 0x0 + +# FIXME: We can't get N32 correct at the moment. If we use a mips-* triple then +# we incorrectly drop the addend. If we use a mips64-* triple then we +# incorrectly use the 3-reloc encoding (and ELF64). mips64-* triples +# are closest to being correct so we use them for now. +# This should be corrected once the triple bugfixes allow us to be ABI +# dependent rather than triple dependent. +# OBJ-N32-LABEL: Name: .text +# OBJ-N32: 0000: 00000000 00000000 00000000 +# OBJ-N32-LABEL: } +# OBJ-N32-LABEL: Relocations [ +# OBJ-N32: 0x0 R_MIPS_NONE/R_MIPS_NONE/R_MIPS_NONE foo 0x4 +# OBJ-N32: 0x4 R_MIPS_NONE/R_MIPS_NONE/R_MIPS_NONE foo 0x0 +# OBJ-N32: 0x8 R_MIPS_32/R_MIPS_NONE/R_MIPS_NONE .text 0x8 +# OBJ-N32: 0xC R_MIPS_NONE/R_MIPS_NONE/R_MIPS_NONE - 0x0 + +# OBJ-N64-LABEL: Name: .text +# OBJ-N64: 0000: 00000000 00000000 00000000 +# OBJ-N64-LABEL: } +# OBJ-N64-LABEL: Relocations [ +# OBJ-N64: 0x0 R_MIPS_NONE/R_MIPS_NONE/R_MIPS_NONE foo 0x4 +# OBJ-N64: 0x4 R_MIPS_NONE/R_MIPS_NONE/R_MIPS_NONE foo 0x0 +# OBJ-N64: 0x8 R_MIPS_32/R_MIPS_NONE/R_MIPS_NONE .text 0x8 +# OBJ-N64: 0xC R_MIPS_NONE/R_MIPS_NONE/R_MIPS_NONE - 0x0 -- 2.34.1