Implement .reloc (constant offset only) with support for R_MIPS_NONE and R_MIPS_32.
authorDaniel Sanders <daniel.sanders@imgtec.com>
Thu, 12 Nov 2015 13:33:00 +0000 (13:33 +0000)
committerDaniel Sanders <daniel.sanders@imgtec.com>
Thu, 12 Nov 2015 13:33:00 +0000 (13:33 +0000)
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

13 files changed:
include/llvm/MC/MCAsmBackend.h
include/llvm/MC/MCObjectStreamer.h
include/llvm/MC/MCStreamer.h
lib/MC/MCAsmBackend.cpp
lib/MC/MCAsmStreamer.cpp
lib/MC/MCObjectStreamer.cpp
lib/MC/MCParser/AsmParser.cpp
lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp
lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h
lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp
lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h
test/MC/Mips/reloc-directive-bad.s [new file with mode: 0644]
test/MC/Mips/reloc-directive.s [new file with mode: 0644]

index 2bfad2d355b87d6d79213f6a4dd0300c2311e2fd..51312ff80447e3b88cde5c6716359cd0a6819066 100644 (file)
@@ -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;
 
index 3de44f8e7896a31bc0f11122ca715ac0558fbe5c..9fe2fda213533378b76651709faed139e2fe41b0 100644 (file)
@@ -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;
 
index 67e244201131ce034cf60ee00b8fe6989dce7f37..02b9d18af5fd24c062f732d8e593890193ae2f70 100644 (file)
@@ -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);
 
index 36c65b7bcd494c5bcedd30f777ee8758b0abcf2c..fcf139b725379e62328124c39108de17bf3b6f6f 100644 (file)
@@ -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},
index 4f2d1d2229d92b60c2e30c379e479bcf5b8cb6b4..c99ce7752b30178cb0f3be57e3f8cdd6cd8fc26a 100644 (file)
@@ -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.
index c47e2162b63e42074ce34231c434064629861d9a..d0a7dafa15b84e9730ecf6a365573514c737d874 100644 (file)
@@ -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");
index 245ba44a2498e2738dd6e501c162cb1433227306..dd0e6bde9d89a476c41d64cdd7b7d52d4748cb0d 100644 (file)
@@ -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) {
index da16bebba363ebd9d5db7a3433b5392068b67d98..a9b31ac877d282ddf890e0fef0599d2e223579be 100644 (file)
@@ -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 },
index b3d5a4964f86c78e40ec1f623e8f780dfe79402b..1c9af9227ffe5dff6689b1d18be08c3cee0c47a7 100644 (file)
@@ -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 {
index 9b2952720edd32202d0e376db8c6c9833d9b6dc7..864188670a9e8cb5083e0b9fe1519f0832851d6e 100644 (file)
@@ -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;
index e601963264deabad82a5c76eb657692a30bf19de..3652f4bab0d43ff61a74698d1f741491bcd86339 100644 (file)
@@ -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 (file)
index 0000000..41f21ed
--- /dev/null
@@ -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 (file)
index 0000000..f42a1bc
--- /dev/null
@@ -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