[llvm] r255787 - [SystemZ] Sort relocs to avoid code corruption by linker optimization

Rafael EspĂ­ndola via llvm-commits llvm-commits at lists.llvm.org
Wed Dec 16 13:22:07 PST 2015


Are the two relocations created in the correct order? If so, we should
probably change the default sort to use a stable sort and change the
compare function to

static int cmpRel(const ELFRelocationEntry *AP, const ELFRelocationEntry *BP) {
  const ELFRelocationEntry &A = *AP;
  const ELFRelocationEntry &B = *BP;
  if (A.Offset != B.Offset)
    return B.Offset - A.Offset;
  return 0;
}

The function is there just for bug by bug compatibility with gas and
as an easy hack for making the output stable. Ideally we just just
delete it and fix any non deterministic code.

Cheers,
Rafael




On 16 December 2015 at 13:12, Ulrich Weigand via llvm-commits
<llvm-commits at lists.llvm.org> wrote:
> Author: uweigand
> Date: Wed Dec 16 12:12:40 2015
> New Revision: 255787
>
> URL: http://llvm.org/viewvc/llvm-project?rev=255787&view=rev
> Log:
> [SystemZ] Sort relocs to avoid code corruption by linker optimization
>
> The SystemZ linkers provide an optimization to transform a general-
> or local-dynamic TLS sequence into an initial-exec sequence if possible.
> Do do that, the compiler generates a function call to __tls_get_offset,
> which is a brasl instruction annotated with *two* relocations:
>
> - a R_390_PLT32DBL to install __tls_get_offset as branch target
> - a R_390_TLS_GDCALL / R_390_TLS_LDCALL to inform the linker that
>   the TLS optimization should be performed if possible
>
> If the optimization is performed, the brasl is replaced by an ld load
> instruction.
>
> However, *both* relocs are processed independently by the linker.
> Therefore it is crucial that the R_390_PLT32DBL is processed *first*
> (installing the branch target for the brasl) and the R_390_TLS_GDCALL
> is processed *second* (replacing the whole brasl with an ld).
>
> If the relocs are swapped, the linker will first replace the brasl
> with an ld, and *then* install the __tls_get_offset branch target
> offset.  Since ld has a different layout than brasl, this may even
> result in a completely different (or invalid) instruction; in any
> case, the resulting code is corrupted.
>
> Unfortunately, the way the MC common code sorts relocations causes
> these two to *always* end up the wrong way around, resulting in
> wrong code generation by the linker and crashes.
>
> This patch overrides the sortRelocs routine to detect this particular
> pair of relocs and enforce the required order.
>
>
> Modified:
>     llvm/trunk/lib/Target/SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp
>     llvm/trunk/test/MC/SystemZ/fixups.s
>
> Modified: llvm/trunk/lib/Target/SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp?rev=255787&r1=255786&r2=255787&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Target/SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp (original)
> +++ llvm/trunk/lib/Target/SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp Wed Dec 16 12:12:40 2015
> @@ -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::GetRelocTy
>    }
>  }
>
> +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);
>
> Modified: llvm/trunk/test/MC/SystemZ/fixups.s
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/SystemZ/fixups.s?rev=255787&r1=255786&r2=255787&view=diff
> ==============================================================================
> --- llvm/trunk/test/MC/SystemZ/fixups.s (original)
> +++ llvm/trunk/test/MC/SystemZ/fixups.s Wed Dec 16 12:12:40 2015
> @@ -37,16 +37,16 @@
>  # CHECK: brasl %r14, target at PLT:tls_gdcall:sym  # encoding: [0xc0,0xe5,A,A,A,A]
>  # CHECK-NEXT:                                   # fixup A - offset: 2, value: target at PLT+2, kind: FK_390_PC32DBL
>  # CHECK-NEXT:                                   # fixup B - offset: 0, value: sym at 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 at plt:tls_gdcall:sym
>
>  # CHECK: brasl %r14, target at PLT:tls_ldcall:sym  # encoding: [0xc0,0xe5,A,A,A,A]
>  # CHECK-NEXT:                                   # fixup A - offset: 2, value: target at PLT+2, kind: FK_390_PC32DBL
>  # CHECK-NEXT:                                   # fixup B - offset: 0, value: sym at 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 at plt:tls_ldcall:sym
>
> @@ -65,16 +65,16 @@
>  # CHECK: bras %r14, target at PLT:tls_gdcall:sym   # encoding: [0xa7,0xe5,A,A]
>  # CHECK-NEXT:                                   # fixup A - offset: 2, value: target at PLT+2, kind: FK_390_PC16DBL
>  # CHECK-NEXT:                                   # fixup B - offset: 0, value: sym at 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 at plt:tls_gdcall:sym
>
>  # CHECK: bras %r14, target at PLT:tls_ldcall:sym   # encoding: [0xa7,0xe5,A,A]
>  # CHECK-NEXT:                                   # fixup A - offset: 2, value: target at PLT+2, kind: FK_390_PC16DBL
>  # CHECK-NEXT:                                   # fixup B - offset: 0, value: sym at 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 at plt:tls_ldcall:sym
>
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits


More information about the llvm-commits mailing list