summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp')
-rw-r--r--llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp19
1 files changed, 19 insertions, 0 deletions
diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp
index ee1af023769..76a00fccbef 100644
--- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp
+++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp
@@ -26,6 +26,8 @@ protected:
// Override MCELFObjectTargetWriter.
unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup,
bool IsPCRel) const override;
+ void sortRelocs(const MCAssembler &Asm,
+ std::vector<ELFRelocationEntry> &Relocs) override;
};
} // end anonymous namespace
@@ -152,6 +154,23 @@ unsigned SystemZObjectWriter::GetRelocType(const MCValue &Target,
}
}
+void SystemZObjectWriter::sortRelocs(const MCAssembler &Asm,
+ std::vector<ELFRelocationEntry> &Relocs) {
+ // The default function sorts entries by Offset in descending order.
+ MCELFObjectTargetWriter::sortRelocs(Asm, Relocs);
+
+ // This is OK for SystemZ, except for R_390_TLS_GDCALL/LDCALL relocs.
+ // There is typically another reloc, a R_390_PLT32DBL, on the same
+ // instruction. This other reloc must come *before* the GDCALL reloc,
+ // or else the TLS linker optimization may generate incorrect code.
+ for (unsigned i = 0, e = Relocs.size(); i + 1 < e; ++i) {
+ if ((Relocs[i + 1].Type == ELF::R_390_TLS_GDCALL ||
+ Relocs[i + 1].Type == ELF::R_390_TLS_LDCALL) &&
+ Relocs[i].Offset == Relocs[i + 1].Offset + 2)
+ std::swap(Relocs[i], Relocs[i + 1]);
+ }
+}
+
MCObjectWriter *llvm::createSystemZObjectWriter(raw_pwrite_stream &OS,
uint8_t OSABI) {
MCELFObjectTargetWriter *MOTW = new SystemZObjectWriter(OSABI);
OpenPOWER on IntegriCloud