[mips][ias] Support .dtprel[d]word and .tprel[d]word directives

Assembler directives .dtprelword, .dtpreldword, .tprelword, and
.tpreldword generates relocations R_MIPS_TLS_DTPREL32, R_MIPS_TLS_DTPREL64,
R_MIPS_TLS_TPREL32, and R_MIPS_TLS_TPREL64 respectively.

The main motivation for this patch is to be able to write test cases
for checking correctness of the LLD linker's behaviour.

Differential Revision: https://reviews.llvm.org/D23669

llvm-svn: 279439
This commit is contained in:
Simon Atanasyan 2016-08-22 16:18:42 +00:00
parent f8c2f08cb3
commit eb9ed61021
13 changed files with 267 additions and 8 deletions

View File

@ -193,6 +193,14 @@ protected:
/// 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 @@ public:
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

View File

@ -33,6 +33,10 @@ enum MCFixupKind {
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.

View File

@ -136,6 +136,10 @@ public:
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,

View File

@ -569,6 +569,34 @@ public:
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.
///

View File

@ -34,6 +34,10 @@ const MCFixupKindInfo &MCAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
{"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},

View File

@ -180,6 +180,11 @@ public:
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 @@ void MCAsmStreamer::EmitSLEB128Value(const MCExpr *Value) {
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();

View File

@ -445,6 +445,46 @@ void MCObjectStreamer::emitValueToOffset(const MCExpr *Offset,
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();
@ -455,7 +495,7 @@ void MCObjectStreamer::EmitGPRel32Value(const MCExpr *Value) {
DF->getContents().resize(DF->getContents().size() + 4, 0);
}
// Associate GPRel32 fixup with data and resize data area
// Associate GPRel64 fixup with data and resize data area
void MCObjectStreamer::EmitGPRel64Value(const MCExpr *Value) {
MCDataFragment *DF = getOrCreateDataFragment();
flushPendingLabels(DF, DF->getContents().size());

View File

@ -127,6 +127,22 @@ void MCStreamer::EmitSymbolValue(const MCSymbol *Sym, unsigned Size,
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");
}

View File

@ -292,6 +292,10 @@ class MipsAsmParser : public MCTargetAsmParser {
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,
@ -5749,7 +5753,79 @@ bool MipsAsmParser::parseDirectiveGpDWord() {
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;
@ -6304,6 +6380,26 @@ bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) {
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;

View File

@ -59,6 +59,10 @@ static unsigned adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
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:

View File

@ -270,6 +270,14 @@ unsigned MipsELFObjectWriter::getRelocType(MCContext &Ctx,
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;

View File

@ -45,6 +45,10 @@ MipsMCAsmInfo::MipsMCAsmInfo(const Triple &TheTriple) {
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;

View File

@ -167,7 +167,7 @@ baz: .long foo // RELOC: R_MIPS_32 foo
// 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 @@ baz: .long foo // RELOC: R_MIPS_32 foo
// 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 @@ baz: .long foo // RELOC: R_MIPS_32 foo
// 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 @@ baz: .long foo // RELOC: R_MIPS_32 foo
// 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 @@ baz: .long foo // RELOC: R_MIPS_32 foo
// 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 @@ baz: .long foo // RELOC: R_MIPS_32 foo
// 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 @@ baz: .long foo // RELOC: R_MIPS_32 foo
// 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]