Index: include/llvm/MC/MCAsmInfo.h =================================================================== --- include/llvm/MC/MCAsmInfo.h +++ include/llvm/MC/MCAsmInfo.h @@ -193,6 +193,14 @@ /// on Alpha. Defaults to NULL. const char *GPRel32Directive; + /// If non-null, directives that are used to emit a word/dword which should + /// be relocated as a 32/64-bit DTP/TP-relative offset, e.g. .dtprelword/ + /// .dtpreldword/.tprelword/.tpreldword on Mips. + const char *DTPRel32Directive = nullptr; + const char *DTPRel64Directive = nullptr; + const char *TPRel32Directive = nullptr; + const char *TPRel64Directive = nullptr; + /// This is true if this target uses "Sun Style" syntax for section switching /// ("#alloc,#write" etc) instead of the normal ELF syntax (,"a,w") in /// .section directives. Defaults to false. @@ -396,6 +404,10 @@ const char *getData64bitsDirective() const { return Data64bitsDirective; } const char *getGPRel64Directive() const { return GPRel64Directive; } const char *getGPRel32Directive() const { return GPRel32Directive; } + const char *getDTPRel64Directive() const { return DTPRel64Directive; } + const char *getDTPRel32Directive() const { return DTPRel32Directive; } + const char *getTPRel64Directive() const { return TPRel64Directive; } + const char *getTPRel32Directive() const { return TPRel32Directive; } /// Targets can implement this method to specify a section to switch to if the /// translation unit doesn't have any trampolines that require an executable Index: include/llvm/MC/MCFixup.h =================================================================== --- include/llvm/MC/MCFixup.h +++ include/llvm/MC/MCFixup.h @@ -33,6 +33,10 @@ FK_GPRel_2, ///< A two-byte gp relative fixup. FK_GPRel_4, ///< A four-byte gp relative fixup. FK_GPRel_8, ///< A eight-byte gp relative fixup. + FK_DTPRel_4, ///< A four-byte dtp relative fixup. + FK_DTPRel_8, ///< A eight-byte dtp relative fixup. + FK_TPRel_4, ///< A four-byte tp relative fixup. + FK_TPRel_8, ///< A eight-byte tp relative fixup. FK_SecRel_1, ///< A one-byte section relative fixup. FK_SecRel_2, ///< A two-byte section relative fixup. FK_SecRel_4, ///< A four-byte section relative fixup. Index: include/llvm/MC/MCObjectStreamer.h =================================================================== --- include/llvm/MC/MCObjectStreamer.h +++ include/llvm/MC/MCObjectStreamer.h @@ -136,6 +136,10 @@ StringRef FixedSizePortion) override; void EmitCVStringTableDirective() override; void EmitCVFileChecksumsDirective() override; + void EmitDTPRel32Value(const MCExpr *Value) override; + void EmitDTPRel64Value(const MCExpr *Value) override; + void EmitTPRel32Value(const MCExpr *Value) override; + void EmitTPRel64Value(const MCExpr *Value) override; void EmitGPRel32Value(const MCExpr *Value) override; void EmitGPRel64Value(const MCExpr *Value) override; bool EmitRelocDirective(const MCExpr &Offset, StringRef Name, Index: include/llvm/MC/MCStreamer.h =================================================================== --- include/llvm/MC/MCStreamer.h +++ include/llvm/MC/MCStreamer.h @@ -569,6 +569,34 @@ void EmitSymbolValue(const MCSymbol *Sym, unsigned Size, bool IsSectionRelative = false); + /// \brief Emit the expression \p Value into the output as a dtprel + /// (64-bit DTP relative) value. + /// + /// This is used to implement assembler directives such as .dtpreldword on + /// targets that support them. + virtual void EmitDTPRel64Value(const MCExpr *Value); + + /// \brief Emit the expression \p Value into the output as a dtprel + /// (32-bit DTP relative) value. + /// + /// This is used to implement assembler directives such as .dtprelword on + /// targets that support them. + virtual void EmitDTPRel32Value(const MCExpr *Value); + + /// \brief Emit the expression \p Value into the output as a tprel + /// (64-bit TP relative) value. + /// + /// This is used to implement assembler directives such as .tpreldword on + /// targets that support them. + virtual void EmitTPRel64Value(const MCExpr *Value); + + /// \brief Emit the expression \p Value into the output as a tprel + /// (32-bit TP relative) value. + /// + /// This is used to implement assembler directives such as .tprelword on + /// targets that support them. + virtual void EmitTPRel32Value(const MCExpr *Value); + /// \brief Emit the expression \p Value into the output as a gprel64 (64-bit /// GP relative) value. /// Index: lib/MC/MCAsmBackend.cpp =================================================================== --- lib/MC/MCAsmBackend.cpp +++ lib/MC/MCAsmBackend.cpp @@ -34,6 +34,10 @@ {"FK_GPRel_2", 0, 16, 0}, {"FK_GPRel_4", 0, 32, 0}, {"FK_GPRel_8", 0, 64, 0}, + {"FK_DTPRel_4", 0, 32, 0}, + {"FK_DTPRel_8", 0, 64, 0}, + {"FK_TPRel_4", 0, 32, 0}, + {"FK_TPRel_8", 0, 64, 0}, {"FK_SecRel_1", 0, 8, 0}, {"FK_SecRel_2", 0, 16, 0}, {"FK_SecRel_4", 0, 32, 0}, Index: lib/MC/MCAsmStreamer.cpp =================================================================== --- lib/MC/MCAsmStreamer.cpp +++ lib/MC/MCAsmStreamer.cpp @@ -180,6 +180,11 @@ void EmitSLEB128Value(const MCExpr *Value) override; + void EmitDTPRel32Value(const MCExpr *Value) override; + void EmitDTPRel64Value(const MCExpr *Value) override; + void EmitTPRel32Value(const MCExpr *Value) override; + void EmitTPRel64Value(const MCExpr *Value) override; + void EmitGPRel64Value(const MCExpr *Value) override; void EmitGPRel32Value(const MCExpr *Value) override; @@ -856,6 +861,34 @@ EmitEOL(); } +void MCAsmStreamer::EmitDTPRel64Value(const MCExpr *Value) { + assert(MAI->getDTPRel64Directive() != nullptr); + OS << MAI->getDTPRel64Directive(); + Value->print(OS, MAI); + EmitEOL(); +} + +void MCAsmStreamer::EmitDTPRel32Value(const MCExpr *Value) { + assert(MAI->getDTPRel32Directive() != nullptr); + OS << MAI->getDTPRel32Directive(); + Value->print(OS, MAI); + EmitEOL(); +} + +void MCAsmStreamer::EmitTPRel64Value(const MCExpr *Value) { + assert(MAI->getTPRel64Directive() != nullptr); + OS << MAI->getTPRel64Directive(); + Value->print(OS, MAI); + EmitEOL(); +} + +void MCAsmStreamer::EmitTPRel32Value(const MCExpr *Value) { + assert(MAI->getTPRel32Directive() != nullptr); + OS << MAI->getTPRel32Directive(); + Value->print(OS, MAI); + EmitEOL(); +} + void MCAsmStreamer::EmitGPRel64Value(const MCExpr *Value) { assert(MAI->getGPRel64Directive() != nullptr); OS << MAI->getGPRel64Directive(); Index: lib/MC/MCObjectStreamer.cpp =================================================================== --- lib/MC/MCObjectStreamer.cpp +++ lib/MC/MCObjectStreamer.cpp @@ -445,6 +445,46 @@ insert(new MCOrgFragment(*Offset, Value)); } +// Associate DTPRel32 fixup with data and resize data area +void MCObjectStreamer::EmitDTPRel32Value(const MCExpr *Value) { + MCDataFragment *DF = getOrCreateDataFragment(); + flushPendingLabels(DF, DF->getContents().size()); + + DF->getFixups().push_back(MCFixup::create(DF->getContents().size(), + Value, FK_DTPRel_4)); + DF->getContents().resize(DF->getContents().size() + 4, 0); +} + +// Associate DTPRel64 fixup with data and resize data area +void MCObjectStreamer::EmitDTPRel64Value(const MCExpr *Value) { + MCDataFragment *DF = getOrCreateDataFragment(); + flushPendingLabels(DF, DF->getContents().size()); + + DF->getFixups().push_back(MCFixup::create(DF->getContents().size(), + Value, FK_DTPRel_8)); + DF->getContents().resize(DF->getContents().size() + 8, 0); +} + +// Associate TPRel32 fixup with data and resize data area +void MCObjectStreamer::EmitTPRel32Value(const MCExpr *Value) { + MCDataFragment *DF = getOrCreateDataFragment(); + flushPendingLabels(DF, DF->getContents().size()); + + DF->getFixups().push_back(MCFixup::create(DF->getContents().size(), + Value, FK_TPRel_4)); + DF->getContents().resize(DF->getContents().size() + 4, 0); +} + +// Associate TPRel64 fixup with data and resize data area +void MCObjectStreamer::EmitTPRel64Value(const MCExpr *Value) { + MCDataFragment *DF = getOrCreateDataFragment(); + flushPendingLabels(DF, DF->getContents().size()); + + DF->getFixups().push_back(MCFixup::create(DF->getContents().size(), + Value, FK_TPRel_8)); + DF->getContents().resize(DF->getContents().size() + 8, 0); +} + // Associate GPRel32 fixup with data and resize data area void MCObjectStreamer::EmitGPRel32Value(const MCExpr *Value) { MCDataFragment *DF = getOrCreateDataFragment(); Index: lib/MC/MCStreamer.cpp =================================================================== --- lib/MC/MCStreamer.cpp +++ lib/MC/MCStreamer.cpp @@ -127,6 +127,22 @@ EmitCOFFSecRel32(Sym); } +void MCStreamer::EmitDTPRel64Value(const MCExpr *Value) { + report_fatal_error("unsupported directive in streamer"); +} + +void MCStreamer::EmitDTPRel32Value(const MCExpr *Value) { + report_fatal_error("unsupported directive in streamer"); +} + +void MCStreamer::EmitTPRel64Value(const MCExpr *Value) { + report_fatal_error("unsupported directive in streamer"); +} + +void MCStreamer::EmitTPRel32Value(const MCExpr *Value) { + report_fatal_error("unsupported directive in streamer"); +} + void MCStreamer::EmitGPRel64Value(const MCExpr *Value) { report_fatal_error("unsupported directive in streamer"); } Index: lib/Target/Mips/AsmParser/MipsAsmParser.cpp =================================================================== --- lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -292,6 +292,10 @@ bool parseDataDirective(unsigned Size, SMLoc L); bool parseDirectiveGpWord(); bool parseDirectiveGpDWord(); + bool parseDirectiveDtpRelWord(); + bool parseDirectiveDtpRelDWord(); + bool parseDirectiveTpRelWord(); + bool parseDirectiveTpRelDWord(); bool parseDirectiveModule(); bool parseDirectiveModuleFP(); bool parseFpABIValue(MipsABIFlagsSection::FpABIKind &FpABI, @@ -5710,7 +5714,79 @@ getParser().getStreamer().EmitGPRel64Value(Value); if (getLexer().isNot(AsmToken::EndOfStatement)) - return Error(getLexer().getLoc(), + return Error(getLexer().getLoc(), + "unexpected token, expected end of statement"); + Parser.Lex(); // Eat EndOfStatement token. + return false; +} + +/// parseDirectiveDtpRelWord +/// ::= .dtprelword tls_sym +bool MipsAsmParser::parseDirectiveDtpRelWord() { + MCAsmParser &Parser = getParser(); + const MCExpr *Value; + // EmitDTPRel32Value requires an expression, so we are using base class + // method to evaluate the expression. + if (getParser().parseExpression(Value)) + return true; + getParser().getStreamer().EmitDTPRel32Value(Value); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return Error(getLexer().getLoc(), + "unexpected token, expected end of statement"); + Parser.Lex(); // Eat EndOfStatement token. + return false; +} + +/// parseDirectiveDtpRelDWord +/// ::= .dtpreldword tls_sym +bool MipsAsmParser::parseDirectiveDtpRelDWord() { + MCAsmParser &Parser = getParser(); + const MCExpr *Value; + // EmitDTPRel64Value requires an expression, so we are using base class + // method to evaluate the expression. + if (getParser().parseExpression(Value)) + return true; + getParser().getStreamer().EmitDTPRel64Value(Value); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return Error(getLexer().getLoc(), + "unexpected token, expected end of statement"); + Parser.Lex(); // Eat EndOfStatement token. + return false; +} + +/// parseDirectiveTpRelWord +/// ::= .tprelword tls_sym +bool MipsAsmParser::parseDirectiveTpRelWord() { + MCAsmParser &Parser = getParser(); + const MCExpr *Value; + // EmitTPRel32Value requires an expression, so we are using base class + // method to evaluate the expression. + if (getParser().parseExpression(Value)) + return true; + getParser().getStreamer().EmitTPRel32Value(Value); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return Error(getLexer().getLoc(), + "unexpected token, expected end of statement"); + Parser.Lex(); // Eat EndOfStatement token. + return false; +} + +/// parseDirectiveTpRelDWord +/// ::= .tpreldword tls_sym +bool MipsAsmParser::parseDirectiveTpRelDWord() { + MCAsmParser &Parser = getParser(); + const MCExpr *Value; + // EmitTPRel64Value requires an expression, so we are using base class + // method to evaluate the expression. + if (getParser().parseExpression(Value)) + return true; + getParser().getStreamer().EmitTPRel64Value(Value); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return Error(getLexer().getLoc(), "unexpected token, expected end of statement"); Parser.Lex(); // Eat EndOfStatement token. return false; @@ -6265,6 +6341,26 @@ return false; } + if (IDVal == ".dtprelword") { + parseDirectiveDtpRelWord(); + return false; + } + + if (IDVal == ".dtpreldword") { + parseDirectiveDtpRelDWord(); + return false; + } + + if (IDVal == ".tprelword") { + parseDirectiveTpRelWord(); + return false; + } + + if (IDVal == ".tpreldword") { + parseDirectiveTpRelDWord(); + return false; + } + if (IDVal == ".word") { parseDataDirective(4, DirectiveID.getLoc()); return false; Index: lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp +++ lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp @@ -59,6 +59,10 @@ case Mips::fixup_MIPS_PCLO16: Value &= 0xffff; break; + case FK_DTPRel_4: + case FK_DTPRel_8: + case FK_TPRel_4: + case FK_TPRel_8: case FK_GPRel_4: case FK_Data_4: case FK_Data_8: Index: lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp +++ lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp @@ -270,6 +270,14 @@ case Mips::fixup_Mips_64: case FK_Data_8: return ELF::R_MIPS_64; + case FK_DTPRel_4: + return ELF::R_MIPS_TLS_DTPREL32; + case FK_DTPRel_8: + return ELF::R_MIPS_TLS_DTPREL64; + case FK_TPRel_4: + return ELF::R_MIPS_TLS_TPREL32; + case FK_TPRel_8: + return ELF::R_MIPS_TLS_TPREL64; case FK_GPRel_4: if (isN64()) { unsigned Type = (unsigned)ELF::R_MIPS_NONE; Index: lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp +++ lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp @@ -45,6 +45,10 @@ ZeroDirective = "\t.space\t"; GPRel32Directive = "\t.gpword\t"; GPRel64Directive = "\t.gpdword\t"; + DTPRel32Directive = "\t.dtprelword\t"; + DTPRel64Directive = "\t.dtpreldword\t"; + TPRel32Directive = "\t.tprelword\t"; + TPRel64Directive = "\t.tpreldword\t"; UseAssignmentForEHBegin = true; SupportsDebugInformation = true; ExceptionsType = ExceptionHandling::DwarfCFI; Index: test/MC/Mips/relocation.s =================================================================== --- test/MC/Mips/relocation.s +++ test/MC/Mips/relocation.s @@ -167,7 +167,7 @@ // ENCLE: daddiu $2, $3, %higher(foo) # encoding: [A,A,0x62,0x64] // FIXUP: # fixup A - offset: 0, value: %higher(foo), kind: fixup_Mips_HIGHER -// DATA-NEXT: 0080: 64620000 24620000 24620000 24620000 +// DATA-NEXT: 0080: 64620000 24620000 24620000 00000000 daddiu $2, $3, %highest(foo) // RELOC: R_MIPS_HIGHEST foo // ENCBE: daddiu $2, $3, %highest(foo) # encoding: [0x64,0x62,A,A] // ENCLE: daddiu $2, $3, %highest(foo) # encoding: [A,A,0x62,0x64] @@ -179,7 +179,6 @@ // ENCLE: addiu $2, $3, %call_hi(foo) # encoding: [A,A,0x62,0x24] // FIXUP: # fixup A - offset: 0, value: %call_hi(foo), kind: fixup_Mips_CALL_HI16 -// DATA-NEXT: 0090: 24620000 24620000 24620000 24620000 addiu $2, $3, %call_lo(foo) // RELOC: R_MIPS_CALL_LO16 foo // ENCBE: addiu $2, $3, %call_lo(foo) # encoding: [0x24,0x62,A,A] // ENCLE: addiu $2, $3, %call_lo(foo) # encoding: [A,A,0x62,0x24] @@ -193,9 +192,11 @@ // jalr $25 // ?????: R_MIPS_JALR foo // ?????: R_MIPS_TLS_DTPMOD32 foo -// .dtprelword foo // FIXME: R_MIPS_TLS_DTPREL32 foo + .dtprelword foo // RELOC: R_MIPS_TLS_DTPREL32 foo + +// DATA-NEXT: 0090: 00000000 00000000 24620000 24620000 // ?????: R_MIPS_TLS_DTPMOD64 foo -// .dtpreldword foo // FIXME: R_MIPS_TLS_DTPREL64 foo + .dtpreldword foo // RELOC: R_MIPS_TLS_DTPREL64 foo addiu $2, $3, %tlsgd(foo) // RELOC: R_MIPS_TLS_GD foo // ENCBE: addiu $2, $3, %tlsgd(foo) # encoding: [0x24,0x62,A,A] // ENCLE: addiu $2, $3, %tlsgd(foo) # encoding: [A,A,0x62,0x24] @@ -206,6 +207,7 @@ // ENCLE: addiu $2, $3, %tlsldm(foo) # encoding: [A,A,0x62,0x24] // FIXUP: # fixup A - offset: 0, value: %tlsldm(foo), kind: fixup_Mips_TLSLDM +// DATA-NEXT: 00A0: 24620000 24620000 24620000 00000000 addiu $2, $3, %dtprel_hi(foo) // RELOC: R_MIPS_TLS_DTPREL_HI16 foo // ENCBE: addiu $2, $3, %dtprel_hi(foo) # encoding: [0x24,0x62,A,A] // ENCLE: addiu $2, $3, %dtprel_hi(foo) # encoding: [A,A,0x62,0x24] @@ -221,8 +223,10 @@ // ENCLE: addiu $2, $3, %gottprel(foo) # encoding: [A,A,0x62,0x24] // FIXUP: # fixup A - offset: 0, value: %gottprel(foo), kind: fixup_Mips_GOTTPREL -// .tprelword foo // FIXME: R_MIPS_TLS_TPREL32 foo -// .tpreldword foo // FIXME: R_MIPS_TLS_TPREL64 foo + .tprelword foo // RELOC: R_MIPS_TLS_TPREL32 foo + +// DATA-NEXT: 00B0: 00000000 00000000 24620000 24620000 + .tpreldword foo // RELOC: R_MIPS_TLS_TPREL64 foo addiu $2, $3, %tprel_hi(foo) // RELOC: R_MIPS_TLS_TPREL_HI16 foo // ENCBE: addiu $2, $3, %tprel_hi(foo) # encoding: [0x24,0x62,A,A] // ENCLE: addiu $2, $3, %tprel_hi(foo) # encoding: [A,A,0x62,0x24] @@ -233,6 +237,7 @@ // ENCLE: addiu $2, $3, %tprel_lo(foo) # encoding: [A,A,0x62,0x24] // FIXUP: # fixup A - offset: 0, value: %tprel_lo(foo), kind: fixup_Mips_TPREL_LO +// DATA-NEXT: 00C0: D85FFFFF CBFFFFFF EC580000 EC480000 // ?????: R_MIPS_GLOB_DAT foo .set mips32r6 beqzc $2, foo // RELOC: R_MIPS_PC21_S2 foo @@ -257,6 +262,7 @@ // ENCLE: lwpc $2, foo # encoding: [A,A,0b01001AAA,0xec] // FIXUP: # fixup A - offset: 0, value: foo, kind: fixup_MIPS_PC19_S2 +// DATA-NEXT: 00D0: 24620000 24620000 00000000 addiu $2, $3, %pcrel_hi(foo) // RELOC: R_MIPS_PCHI16 foo // ENCBE: addiu $2, $3, %pcrel_hi(foo) # encoding: [0x24,0x62,A,A] // ENCLE: addiu $2, $3, %pcrel_hi(foo) # encoding: [A,A,0x62,0x24]