Index: include/llvm/MC/MCAsmBackend.h =================================================================== --- include/llvm/MC/MCAsmBackend.h +++ include/llvm/MC/MCAsmBackend.h @@ -96,6 +96,10 @@ /// getNumFixupKinds - Get the number of target specific fixup kinds. virtual unsigned getNumFixupKinds() const = 0; + virtual unsigned getFixupKind(StringRef Reloc) const { + llvm_unreachable("not implemented"); + } + /// getFixupKindInfo - Get information on a fixup kind. virtual const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const; Index: include/llvm/MC/MCAssembler.h =================================================================== --- include/llvm/MC/MCAssembler.h +++ include/llvm/MC/MCAssembler.h @@ -804,6 +804,27 @@ MCSymbol *End; }; +// Information about relocations generated by directive .reloc. +struct RelocInfo { + RelocInfo(const MCExpr *Offset_, unsigned Kind_, const MCExpr *Value_, + MCSectionData *SectionData_, SMLoc Loc_) + : Offset(Offset_), Kind(Kind_), Value(Value_), + SectionData(SectionData_), Loc(Loc_) {} + // Offset expression. + const MCExpr *Offset; + + // Relocation kind. + unsigned Kind; + + // Value expression. + const MCExpr *Value; + + // Section in which this .reloc appeared. + MCSectionData *SectionData; + + SMLoc Loc; +}; + class MCAssembler { friend class MCAsmLayout; @@ -846,6 +867,9 @@ iplist Symbols; + /// List of .reloc directives. + SmallVector Relocs; + /// The map of sections to their associated assembler backend data. // // FIXME: Avoid this indirection? @@ -939,6 +963,11 @@ uint64_t handleFixup(const MCAsmLayout &Layout, MCFragment &F, const MCFixup &Fixup); + /// Return the fragment to which RI's relocation is applied and the offset + /// relative to the beginning of the fragment. + std::pair + getFragmentAndOffset(const RelocInfo &RI); + public: /// Compute the effective fragment size assuming it is laid out at the given /// \p SectionAddress and \p FragmentOffset. @@ -1030,6 +1059,8 @@ BundleAlignSize = Size; } + SmallVectorImpl &getRelocList() { return Relocs; } + /// @name Section List Access /// @{ Index: include/llvm/MC/MCObjectStreamer.h =================================================================== --- include/llvm/MC/MCObjectStreamer.h +++ include/llvm/MC/MCObjectStreamer.h @@ -87,6 +87,9 @@ const MCExpr *Subsection); virtual void EmitInstruction(const MCInst &Inst); + virtual void EmitReloc(const MCExpr *Offset, StringRef Reloc, + const MCExpr *Expression, SMLoc Loc); + /// \brief Emit an instruction to a special fragment, because this instruction /// can change its size during relaxation. virtual void EmitInstToFragment(const MCInst &Inst); Index: include/llvm/MC/MCStreamer.h =================================================================== --- include/llvm/MC/MCStreamer.h +++ include/llvm/MC/MCStreamer.h @@ -356,6 +356,12 @@ /// a Thumb mode function (ARM target only). virtual void EmitThumbFunc(MCSymbol *Func) = 0; + // Emit .reloc directive. + virtual void EmitReloc(const MCExpr *Offset, StringRef Reloc, + const MCExpr *Expression, SMLoc Loc) { + llvm_unreachable("not implemented"); + } + /// getOrCreateSymbolData - Get symbol data for given symbol. virtual MCSymbolData &getOrCreateSymbolData(MCSymbol *Symbol); Index: include/llvm/Object/ELFObjectFile.h =================================================================== --- include/llvm/Object/ELFObjectFile.h +++ include/llvm/Object/ELFObjectFile.h @@ -783,6 +783,7 @@ } case ELF::EM_ARM: case ELF::EM_HEXAGON: + case ELF::EM_MIPS: res = *SymName; break; default: Index: lib/MC/MCAsmStreamer.cpp =================================================================== --- lib/MC/MCAsmStreamer.cpp +++ lib/MC/MCAsmStreamer.cpp @@ -143,6 +143,8 @@ virtual void EmitLinkerOptions(ArrayRef Options); virtual void EmitDataRegion(MCDataRegionType Kind); virtual void EmitThumbFunc(MCSymbol *Func); + virtual void EmitReloc(const MCExpr *Offset, StringRef Reloc, + const MCExpr *Expression, SMLoc Loc); virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value); virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol); @@ -391,6 +393,11 @@ EmitEOL(); } +void MCAsmStreamer::EmitReloc(const MCExpr *Offset, StringRef Reloc, + const MCExpr *Expression, SMLoc Loc) { + OS << "\t.reloc\t" << *Offset << ", " << Reloc << ", " << *Expression << "\n"; +} + void MCAsmStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { OS << *Symbol << " = " << *Value; EmitEOL(); Index: lib/MC/MCAssembler.cpp =================================================================== --- lib/MC/MCAssembler.cpp +++ lib/MC/MCAssembler.cpp @@ -801,6 +801,15 @@ // example, to set the index fields in the symbol data). getWriter().ExecutePostLayoutBinding(*this, Layout); + // Add fixups generated by directive ".reloc". + for (SmallVectorImpl::const_iterator I = Relocs.begin(), + E = Relocs.end(); I != E; ++I) { + std::pair P = + getFragmentAndOffset(*I); + MCFixup Fixup = MCFixup::Create(P.second, I->Value, (MCFixupKind)I->Kind); + P.first->getFixups().push_back(Fixup); + } + // Evaluate and apply the fixups, generating relocation entries as necessary. for (MCAssembler::iterator it = begin(), ie = end(); it != ie; ++it) { for (MCSectionData::iterator it2 = it->begin(), @@ -825,6 +834,54 @@ stats::ObjectBytes += OS.tell() - StartOffset; } +std::pair +MCAssembler::getFragmentAndOffset(const RelocInfo &RI) { + MCValue OffsetVal; + MCAsmLayout Layout(*this); + + if (!RI.Offset->EvaluateAsRelocatable(OffsetVal, Layout)) + getContext().FatalError(RI.Loc, "unable to evaluate offset"); + + MCSectionData *SD; + int64_t Offset = OffsetVal.getConstant(); + + if (OffsetVal.isAbsolute()) { + // If offset evaluates to an absolute, relocation is generated in the + // section in which the .reloc directive appeared. + assert(RI.SectionData); + SD = RI.SectionData; + } else { + // If offset evaluates to symbol+offset, relocation is generated in the + // given symbol's section. + MCSymbolData *SymData = &getSymbolData(OffsetVal.getSymA()->getSymbol()); + Offset += Layout.getSymbolOffset(SymData); + SD = SymData->getFragment()->getParent(); + } + + if (Offset < 0) + getContext().FatalError(RI.Loc, "offset of .reloc cannot be negative"); + + MCEncodedFragmentWithFixups *F = 0; + uint64_t FragOffset; + + // Find the fragment to which the relocation is applied. + for (MCSectionData::iterator I = SD->begin(), E = SD->end(); I != E; ++I) { + FragOffset = Layout.getFragmentOffset(&*I); + + if (FragOffset <= (uint64_t)Offset && + FragOffset + computeFragmentSize(Layout, *I) > (uint64_t)Offset) { + F = dyn_cast(&*I); + break; + } + } + + if (!F) + getContext().FatalError(RI.Loc, "cannot find a fragment to which this " + "relocation can be applied"); + + return std::make_pair(F, Offset - FragOffset); +} + bool MCAssembler::fixupNeedsRelaxation(const MCFixup &Fixup, const MCRelaxableFragment *DF, const MCAsmLayout &Layout) const { Index: lib/MC/MCObjectStreamer.cpp =================================================================== --- lib/MC/MCObjectStreamer.cpp +++ lib/MC/MCObjectStreamer.cpp @@ -231,6 +231,13 @@ EmitInstToFragment(Inst); } +void MCObjectStreamer::EmitReloc(const MCExpr *Offset, StringRef Reloc, + const MCExpr *Expression, SMLoc Loc) { + unsigned Kind = getAssembler().getBackend().getFixupKind(Reloc); + RelocInfo R(Offset, Kind, Expression, getCurrentSectionData(), Loc); + getAssembler().getRelocList().push_back(R); +} + void MCObjectStreamer::EmitInstToFragment(const MCInst &Inst) { // Always create a new, separate fragment here, because its size can change // during relaxation. Index: lib/MC/MCParser/AsmParser.cpp =================================================================== --- lib/MC/MCParser/AsmParser.cpp +++ lib/MC/MCParser/AsmParser.cpp @@ -350,7 +350,7 @@ DK_INCLUDE, DK_INCBIN, DK_CODE16, DK_CODE16GCC, DK_REPT, DK_IRP, DK_IRPC, DK_IF, DK_IFB, DK_IFNB, DK_IFC, DK_IFNC, DK_IFDEF, DK_IFNDEF, DK_IFNOTDEF, DK_ELSEIF, DK_ELSE, DK_ENDIF, - DK_SPACE, DK_SKIP, DK_FILE, DK_LINE, DK_LOC, DK_STABS, + DK_SPACE, DK_SKIP, DK_FILE, DK_LINE, DK_LOC, DK_STABS, DK_RELOC, DK_CFI_SECTIONS, DK_CFI_STARTPROC, DK_CFI_ENDPROC, DK_CFI_DEF_CFA, DK_CFI_DEF_CFA_OFFSET, DK_CFI_ADJUST_CFA_OFFSET, DK_CFI_DEF_CFA_REGISTER, DK_CFI_OFFSET, DK_CFI_REL_OFFSET, DK_CFI_PERSONALITY, DK_CFI_LSDA, @@ -383,6 +383,9 @@ bool parseDirectiveLoc(); bool parseDirectiveStabs(); + // ".reloc" + bool parseDirectiveReloc(); + // .cfi directives bool parseDirectiveCFIRegister(SMLoc DirectiveLoc); bool parseDirectiveCFIWindowSave(); @@ -1458,6 +1461,8 @@ return parseDirectiveLoc(); case DK_STABS: return parseDirectiveStabs(); + case DK_RELOC: + return parseDirectiveReloc(); case DK_CFI_SECTIONS: return parseDirectiveCFISections(); case DK_CFI_STARTPROC: @@ -2747,6 +2752,35 @@ return TokError("unsupported directive '.stabs'"); } +/// parseDirectiveReloc +/// ::= .reloc expression, string, expression +bool AsmParser::parseDirectiveReloc() { + const MCExpr *Offset, *Value; + StringRef RelocStr; + + if (parseExpression(Offset)) + return true; + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in reloc directive"); + + Lex(); + + if (parseIdentifier(RelocStr)) + return true; + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in reloc directive"); + + Lex(); + + if (parseExpression(Value)) + return true; + + getStreamer().EmitReloc(Offset, RelocStr, Value, getLexer().getLoc()); + return false; +} + /// parseDirectiveCFISections /// ::= .cfi_sections section [, section] bool AsmParser::parseDirectiveCFISections() { @@ -3835,6 +3869,7 @@ DirectiveKindMap[".line"] = DK_LINE; DirectiveKindMap[".loc"] = DK_LOC; DirectiveKindMap[".stabs"] = DK_STABS; + DirectiveKindMap[".reloc"] = DK_RELOC; DirectiveKindMap[".sleb128"] = DK_SLEB128; DirectiveKindMap[".uleb128"] = DK_ULEB128; DirectiveKindMap[".cfi_sections"] = DK_CFI_SECTIONS; Index: lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp +++ lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp @@ -14,6 +14,7 @@ #include "MipsFixupKinds.h" #include "MCTargetDesc/MipsMCTargetDesc.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCDirectives.h" @@ -201,6 +202,7 @@ { "fixup_Mips_GOT_LO16", 0, 16, 0 }, { "fixup_Mips_CALL_HI16", 0, 16, 0 }, { "fixup_Mips_CALL_LO16", 0, 16, 0 }, + { "fixup_Mips_JALR", 0, 16, 0 }, { "fixup_MICROMIPS_26_S1", 0, 26, 0 }, { "fixup_MICROMIPS_HI16", 0, 16, 0 }, { "fixup_MICROMIPS_LO16", 0, 16, 0 }, @@ -224,6 +226,16 @@ return Infos[Kind - FirstTargetFixupKind]; } + unsigned getFixupKind(StringRef Reloc) const { + Mips::Fixups Kind = StringSwitch(Reloc) + .Case("R_MIPS_JALR", Mips::fixup_Mips_JALR) + .Default(Mips::LastTargetFixupKind); + + assert(Kind != Mips::LastTargetFixupKind && "Unknown relocation."); + + return Kind; + } + /// @name Target Relaxation Interfaces /// @{ Index: lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp +++ lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp @@ -68,6 +68,9 @@ assert(Target.getSymA() && "SymA cannot be 0."); const MCSymbol &Sym = Target.getSymA()->getSymbol().AliasedSymbol(); + if ((llvm::Mips::Fixups)Fixup.getKind() == Mips::fixup_Mips_JALR) + return &Sym; + if (Sym.getSection().getKind().isMergeableCString() || Sym.getSection().getKind().isMergeableConst()) return &Sym; @@ -183,6 +186,9 @@ case Mips::fixup_Mips_CALL_LO16: Type = ELF::R_MIPS_CALL_LO16; break; + case Mips::fixup_Mips_JALR: + Type = ELF::R_MIPS_JALR; + break; case Mips::fixup_MICROMIPS_26_S1: Type = ELF::R_MICROMIPS_26_S1; break; Index: lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h +++ lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h @@ -128,6 +128,9 @@ // resulting in - R_MIPS_CALL_LO16 fixup_Mips_CALL_LO16, + // resulting in - R_MIPS_JALR + fixup_Mips_JALR, + // resulting in - R_MICROMIPS_26_S1 fixup_MICROMIPS_26_S1, Index: test/MC/Mips/reloc.s =================================================================== --- /dev/null +++ test/MC/Mips/reloc.s @@ -0,0 +1,46 @@ +// RUN: llvm-mc -filetype=obj %s -o %t.o -arch=mips +// RUN: llvm-objdump -r %t.o | FileCheck %s + +// CHECK: RELOCATION RECORDS FOR [.rel.text]: +// CHECK: 0 R_MIPS_JALR s2 +// CHECK: 4 R_MIPS_JALR s0 +// CHECK: 8 R_MIPS_JALR s5 +// CHECK: 12 R_MIPS_JALR s1 + +// CHECK: RELOCATION RECORDS FOR [.rel.data]: +// CHECK: 4 R_MIPS_JALR s8 +// CHECK: 12 R_MIPS_JALR s3 +// CHECK: 18 R_MIPS_JALR s4 +// CHECK: 20 R_MIPS_JALR s7 + +.text +.reloc 4, R_MIPS_JALR, s0 +.reloc s1+4, R_MIPS_JALR, s7 +.reloc 0, R_MIPS_JALR, s2 +.reloc s5-4, R_MIPS_JALR, s1 +s4: + .long 0,0,0,0 +s5: + .long 0,0,0,0 +s6: + .long 0,0,0,0 +s7: + .long 0,0,0,0 +s8: + .long 0,0,0,0 + +.data +.reloc 4, R_MIPS_JALR, s8 +.reloc s0+18, R_MIPS_JALR, s4 +.reloc s1-4, R_MIPS_JALR, s3 +.reloc s4+8, R_MIPS_JALR, s5 +s0: + .long 0,0,0,0 +s1: + .long 0,0,0,0 +s2: + .long 0,0,0,0 + .long 0,0,0,0 +s3: + .long 0,0,0,0 +