diff --git a/lib/Target/SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp b/lib/Target/SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp index ee1af023769..76a00fccbef 100644 --- a/lib/Target/SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp +++ b/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 &Relocs) override; }; } // end anonymous namespace @@ -152,6 +154,23 @@ unsigned SystemZObjectWriter::GetRelocType(const MCValue &Target, } } +void SystemZObjectWriter::sortRelocs(const MCAssembler &Asm, + std::vector &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); diff --git a/test/MC/SystemZ/fixups.s b/test/MC/SystemZ/fixups.s index 8354121a01e..ea3b690d253 100644 --- a/test/MC/SystemZ/fixups.s +++ b/test/MC/SystemZ/fixups.s @@ -37,16 +37,16 @@ # CHECK: brasl %r14, target@PLT:tls_gdcall:sym # encoding: [0xc0,0xe5,A,A,A,A] # CHECK-NEXT: # fixup A - offset: 2, value: target@PLT+2, kind: FK_390_PC32DBL # CHECK-NEXT: # fixup B - offset: 0, value: sym@TLSGD, kind: FK_390_TLS_CALL -# CHECK-REL: 0x{{[0-9A-F]*0}} R_390_TLS_GDCALL sym 0x0 # CHECK-REL: 0x{{[0-9A-F]*2}} R_390_PLT32DBL target 0x2 +# CHECK-REL: 0x{{[0-9A-F]*0}} R_390_TLS_GDCALL sym 0x0 .align 16 brasl %r14, target@plt:tls_gdcall:sym # CHECK: brasl %r14, target@PLT:tls_ldcall:sym # encoding: [0xc0,0xe5,A,A,A,A] # CHECK-NEXT: # fixup A - offset: 2, value: target@PLT+2, kind: FK_390_PC32DBL # CHECK-NEXT: # fixup B - offset: 0, value: sym@TLSLDM, kind: FK_390_TLS_CALL -# CHECK-REL: 0x{{[0-9A-F]*0}} R_390_TLS_LDCALL sym 0x0 # CHECK-REL: 0x{{[0-9A-F]*2}} R_390_PLT32DBL target 0x2 +# CHECK-REL: 0x{{[0-9A-F]*0}} R_390_TLS_LDCALL sym 0x0 .align 16 brasl %r14, target@plt:tls_ldcall:sym @@ -65,16 +65,16 @@ # CHECK: bras %r14, target@PLT:tls_gdcall:sym # encoding: [0xa7,0xe5,A,A] # CHECK-NEXT: # fixup A - offset: 2, value: target@PLT+2, kind: FK_390_PC16DBL # CHECK-NEXT: # fixup B - offset: 0, value: sym@TLSGD, kind: FK_390_TLS_CALL -# CHECK-REL: 0x{{[0-9A-F]*0}} R_390_TLS_GDCALL sym 0x0 # CHECK-REL: 0x{{[0-9A-F]*2}} R_390_PLT16DBL target 0x2 +# CHECK-REL: 0x{{[0-9A-F]*0}} R_390_TLS_GDCALL sym 0x0 .align 16 bras %r14, target@plt:tls_gdcall:sym # CHECK: bras %r14, target@PLT:tls_ldcall:sym # encoding: [0xa7,0xe5,A,A] # CHECK-NEXT: # fixup A - offset: 2, value: target@PLT+2, kind: FK_390_PC16DBL # CHECK-NEXT: # fixup B - offset: 0, value: sym@TLSLDM, kind: FK_390_TLS_CALL -# CHECK-REL: 0x{{[0-9A-F]*0}} R_390_TLS_LDCALL sym 0x0 # CHECK-REL: 0x{{[0-9A-F]*2}} R_390_PLT16DBL target 0x2 +# CHECK-REL: 0x{{[0-9A-F]*0}} R_390_TLS_LDCALL sym 0x0 .align 16 bras %r14, target@plt:tls_ldcall:sym