Skip to content

Commit 88a7a2e

Browse files
committed
[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. llvm-svn: 255787
1 parent 47f3649 commit 88a7a2e

File tree

2 files changed

+23
-4
lines changed

2 files changed

+23
-4
lines changed

llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ class SystemZObjectWriter : public MCELFObjectTargetWriter {
2626
// Override MCELFObjectTargetWriter.
2727
unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup,
2828
bool IsPCRel) const override;
29+
void sortRelocs(const MCAssembler &Asm,
30+
std::vector<ELFRelocationEntry> &Relocs) override;
2931
};
3032
} // end anonymous namespace
3133

@@ -152,6 +154,23 @@ unsigned SystemZObjectWriter::GetRelocType(const MCValue &Target,
152154
}
153155
}
154156

157+
void SystemZObjectWriter::sortRelocs(const MCAssembler &Asm,
158+
std::vector<ELFRelocationEntry> &Relocs) {
159+
// The default function sorts entries by Offset in descending order.
160+
MCELFObjectTargetWriter::sortRelocs(Asm, Relocs);
161+
162+
// This is OK for SystemZ, except for R_390_TLS_GDCALL/LDCALL relocs.
163+
// There is typically another reloc, a R_390_PLT32DBL, on the same
164+
// instruction. This other reloc must come *before* the GDCALL reloc,
165+
// or else the TLS linker optimization may generate incorrect code.
166+
for (unsigned i = 0, e = Relocs.size(); i + 1 < e; ++i) {
167+
if ((Relocs[i + 1].Type == ELF::R_390_TLS_GDCALL ||
168+
Relocs[i + 1].Type == ELF::R_390_TLS_LDCALL) &&
169+
Relocs[i].Offset == Relocs[i + 1].Offset + 2)
170+
std::swap(Relocs[i], Relocs[i + 1]);
171+
}
172+
}
173+
155174
MCObjectWriter *llvm::createSystemZObjectWriter(raw_pwrite_stream &OS,
156175
uint8_t OSABI) {
157176
MCELFObjectTargetWriter *MOTW = new SystemZObjectWriter(OSABI);

llvm/test/MC/SystemZ/fixups.s

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,16 @@
3737
# CHECK: brasl %r14, target@PLT:tls_gdcall:sym # encoding: [0xc0,0xe5,A,A,A,A]
3838
# CHECK-NEXT: # fixup A - offset: 2, value: target@PLT+2, kind: FK_390_PC32DBL
3939
# CHECK-NEXT: # fixup B - offset: 0, value: sym@TLSGD, kind: FK_390_TLS_CALL
40-
# CHECK-REL: 0x{{[0-9A-F]*0}} R_390_TLS_GDCALL sym 0x0
4140
# CHECK-REL: 0x{{[0-9A-F]*2}} R_390_PLT32DBL target 0x2
41+
# CHECK-REL: 0x{{[0-9A-F]*0}} R_390_TLS_GDCALL sym 0x0
4242
.align 16
4343
brasl %r14, target@plt:tls_gdcall:sym
4444

4545
# CHECK: brasl %r14, target@PLT:tls_ldcall:sym # encoding: [0xc0,0xe5,A,A,A,A]
4646
# CHECK-NEXT: # fixup A - offset: 2, value: target@PLT+2, kind: FK_390_PC32DBL
4747
# CHECK-NEXT: # fixup B - offset: 0, value: sym@TLSLDM, kind: FK_390_TLS_CALL
48-
# CHECK-REL: 0x{{[0-9A-F]*0}} R_390_TLS_LDCALL sym 0x0
4948
# CHECK-REL: 0x{{[0-9A-F]*2}} R_390_PLT32DBL target 0x2
49+
# CHECK-REL: 0x{{[0-9A-F]*0}} R_390_TLS_LDCALL sym 0x0
5050
.align 16
5151
brasl %r14, target@plt:tls_ldcall:sym
5252

@@ -65,16 +65,16 @@
6565
# CHECK: bras %r14, target@PLT:tls_gdcall:sym # encoding: [0xa7,0xe5,A,A]
6666
# CHECK-NEXT: # fixup A - offset: 2, value: target@PLT+2, kind: FK_390_PC16DBL
6767
# CHECK-NEXT: # fixup B - offset: 0, value: sym@TLSGD, kind: FK_390_TLS_CALL
68-
# CHECK-REL: 0x{{[0-9A-F]*0}} R_390_TLS_GDCALL sym 0x0
6968
# CHECK-REL: 0x{{[0-9A-F]*2}} R_390_PLT16DBL target 0x2
69+
# CHECK-REL: 0x{{[0-9A-F]*0}} R_390_TLS_GDCALL sym 0x0
7070
.align 16
7171
bras %r14, target@plt:tls_gdcall:sym
7272

7373
# CHECK: bras %r14, target@PLT:tls_ldcall:sym # encoding: [0xa7,0xe5,A,A]
7474
# CHECK-NEXT: # fixup A - offset: 2, value: target@PLT+2, kind: FK_390_PC16DBL
7575
# CHECK-NEXT: # fixup B - offset: 0, value: sym@TLSLDM, kind: FK_390_TLS_CALL
76-
# CHECK-REL: 0x{{[0-9A-F]*0}} R_390_TLS_LDCALL sym 0x0
7776
# CHECK-REL: 0x{{[0-9A-F]*2}} R_390_PLT16DBL target 0x2
77+
# CHECK-REL: 0x{{[0-9A-F]*0}} R_390_TLS_LDCALL sym 0x0
7878
.align 16
7979
bras %r14, target@plt:tls_ldcall:sym
8080

0 commit comments

Comments
 (0)