Index: llvm/trunk/include/llvm/MC/MCAsmBackend.h =================================================================== --- llvm/trunk/include/llvm/MC/MCAsmBackend.h +++ llvm/trunk/include/llvm/MC/MCAsmBackend.h @@ -67,6 +67,11 @@ /// 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: llvm/trunk/include/llvm/MC/MCObjectStreamer.h =================================================================== --- llvm/trunk/include/llvm/MC/MCObjectStreamer.h +++ llvm/trunk/include/llvm/MC/MCObjectStreamer.h @@ -124,6 +124,8 @@ 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: llvm/trunk/include/llvm/MC/MCStreamer.h =================================================================== --- llvm/trunk/include/llvm/MC/MCStreamer.h +++ llvm/trunk/include/llvm/MC/MCStreamer.h @@ -682,6 +682,14 @@ 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: llvm/trunk/lib/MC/MCAsmBackend.cpp =================================================================== --- llvm/trunk/lib/MC/MCAsmBackend.cpp +++ llvm/trunk/lib/MC/MCAsmBackend.cpp @@ -16,6 +16,10 @@ 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: llvm/trunk/lib/MC/MCAsmStreamer.cpp =================================================================== --- llvm/trunk/lib/MC/MCAsmStreamer.cpp +++ llvm/trunk/lib/MC/MCAsmStreamer.cpp @@ -240,6 +240,9 @@ 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 @@ 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: llvm/trunk/lib/MC/MCObjectStreamer.cpp =================================================================== --- llvm/trunk/lib/MC/MCObjectStreamer.cpp +++ llvm/trunk/lib/MC/MCObjectStreamer.cpp @@ -416,6 +416,26 @@ 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: llvm/trunk/lib/MC/MCParser/AsmParser.cpp =================================================================== --- llvm/trunk/lib/MC/MCParser/AsmParser.cpp +++ llvm/trunk/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 @@ 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 @@ // ".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 @@ 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 @@ 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 @@ DirectiveKindMap[".err"] = DK_ERR; DirectiveKindMap[".error"] = DK_ERROR; DirectiveKindMap[".warning"] = DK_WARNING; + DirectiveKindMap[".reloc"] = DK_RELOC; } MCAsmMacro *AsmParser::parseMacroLikeBody(SMLoc DirectiveLoc) { Index: llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h =================================================================== --- llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h +++ llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h @@ -41,6 +41,7 @@ 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: llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp =================================================================== --- llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp +++ llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp @@ -232,6 +232,18 @@ } } +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 @@ // 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 @@ // 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: llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp =================================================================== --- llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp +++ llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp @@ -68,6 +68,8 @@ 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: llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h =================================================================== --- llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h +++ llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h @@ -23,8 +23,11 @@ // 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, Index: llvm/trunk/test/MC/Mips/reloc-directive-bad.s =================================================================== --- llvm/trunk/test/MC/Mips/reloc-directive-bad.s +++ llvm/trunk/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 Index: llvm/trunk/test/MC/Mips/reloc-directive.s =================================================================== --- llvm/trunk/test/MC/Mips/reloc-directive.s +++ llvm/trunk/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