Index: include/llvm/MC/MCAsmBackend.h =================================================================== --- include/llvm/MC/MCAsmBackend.h +++ 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: include/llvm/MC/MCObjectStreamer.h =================================================================== --- include/llvm/MC/MCObjectStreamer.h +++ 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 EmitZeros(uint64_t NumBytes) override; void FinishImpl() override; Index: include/llvm/MC/MCStreamer.h =================================================================== --- include/llvm/MC/MCStreamer.h +++ include/llvm/MC/MCStreamer.h @@ -684,6 +684,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: lib/MC/MCAsmBackend.cpp =================================================================== --- lib/MC/MCAsmBackend.cpp +++ 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: lib/MC/MCAsmStreamer.cpp =================================================================== --- lib/MC/MCAsmStreamer.cpp +++ lib/MC/MCAsmStreamer.cpp @@ -239,6 +239,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. @@ -1358,6 +1361,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: lib/MC/MCObjectStreamer.cpp =================================================================== --- lib/MC/MCObjectStreamer.cpp +++ lib/MC/MCObjectStreamer.cpp @@ -433,6 +433,25 @@ 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)) { + if (Expr == nullptr) + Expr = MCSymbolRefExpr::create(getContext().createTempSymbol(), getContext()); + DF->getFixups().push_back(MCFixup::create(OffsetValue, Expr, Kind, Loc)); + return false; + } + return true; +} + void MCObjectStreamer::EmitFill(uint64_t NumBytes, uint8_t FillValue) { // FIXME: A MCFillFragment would be more memory efficient but MCExpr has // problems evaluating expressions across multiple fragments. Index: lib/MC/MCParser/AsmParser.cpp =================================================================== --- lib/MC/MCParser/AsmParser.cpp +++ lib/MC/MCParser/AsmParser.cpp @@ -365,7 +365,7 @@ DK_MACRO, DK_EXITM, DK_ENDM, DK_ENDMACRO, DK_PURGEM, DK_SLEB128, DK_ULEB128, DK_ERR, DK_ERROR, DK_WARNING, - DK_END + DK_END, DK_RELOC }; /// \brief Maps directive name --> DirectiveKind enum, for @@ -485,6 +485,9 @@ // ".warning" bool parseDirectiveWarning(SMLoc DirectiveLoc); + // ".reloc" + bool parseDirectiveReloc(SMLoc DirectiveLoc); + void initializeDirectiveKindMap(); }; } @@ -1682,6 +1685,8 @@ return parseDirectiveError(IDLoc, true); case DK_WARNING: return parseDirectiveWarning(IDLoc); + case DK_RELOC: + return parseDirectiveReloc(IDLoc); } return Error(IDLoc, "unknown directive"); @@ -4352,6 +4357,7 @@ DirectiveKindMap[".err"] = DK_ERR; DirectiveKindMap[".error"] = DK_ERROR; DirectiveKindMap[".warning"] = DK_WARNING; + DirectiveKindMap[".reloc"] = DK_RELOC; } MCAsmMacro *AsmParser::parseMacroLikeBody(SMLoc DirectiveLoc) { @@ -4594,6 +4600,44 @@ return false; } +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(); + if (parseExpression(Expr)) + return true; + } + + 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; +} + // We are comparing pointers, but the pointers are relative to a single string. // Thus, this should always be deterministic. static int rewritesSort(const AsmRewrite *AsmRewriteA, Index: lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h +++ 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: lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp +++ 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: lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp +++ 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: lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h +++ 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: test/MC/Mips/reloc-directive.s =================================================================== --- /dev/null +++ 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