[lld] [ELF] Add target-specific relocation scanning for SystemZ (PR #181563)
Fangrui Song via llvm-commits
llvm-commits at lists.llvm.org
Mon Feb 16 11:58:12 PST 2026
================
@@ -265,150 +189,241 @@ int64_t SystemZ::getImplicitAddend(const uint8_t *buf, RelType type) const {
}
}
-RelType SystemZ::getDynRel(RelType type) const {
- if (type == R_390_64 || type == R_390_PC64)
- return type;
- return R_390_NONE;
-}
+template <class ELFT, class RelTy>
+void SystemZ::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels) {
+ RelocScan rs(ctx, &sec);
+ sec.relocations.reserve(rels.size());
+
+ for (auto it = rels.begin(); it != rels.end(); ++it) {
+ RelType type = it->getType(false);
+
+ // The assembler emits R_390_PLT32DBL (at the displacement field) before
+ // R_390_TLS_GDCALL/LDCALL (at the instruction start) for the same brasl.
+ // When optimizing TLS, skip PLT32DBL before maybeReportUndefined would
+ // flag __tls_get_offset as undefined.
+ if (type == R_390_PLT32DBL && !ctx.arg.shared &&
+ std::next(it) != rels.end()) {
+ RelType nextType = std::next(it)->getType(false);
+ if (nextType == R_390_TLS_GDCALL || nextType == R_390_TLS_LDCALL)
+ continue;
+ }
-RelExpr SystemZ::adjustTlsExpr(RelType type, RelExpr expr) const {
- if (expr == R_RELAX_TLS_GD_TO_IE)
- return R_RELAX_TLS_GD_TO_IE_GOT_OFF;
- return expr;
-}
+ uint32_t symIdx = it->getSymbol(false);
+ Symbol &sym = sec.getFile<ELFT>()->getSymbol(symIdx);
+ uint64_t offset = it->r_offset;
+ if (sym.isUndefined() && symIdx != 0 &&
+ rs.maybeReportUndefined(cast<Undefined>(sym), offset))
+ continue;
+ int64_t addend = rs.getAddend<ELFT>(*it, type);
+
+ RelExpr expr;
+ // Relocation types that only need a RelExpr set `expr` and break out of
+ // the switch to reach rs.process(). Types that need special handling
+ // (fast-path helpers, TLS) call a handler and use `continue`.
+ switch (type) {
+ case R_390_NONE:
+ case R_390_TLS_LOAD:
+ continue;
-int SystemZ::getTlsGdRelaxSkip(RelType type) const {
- // A __tls_get_offset call instruction is marked with 2 relocations:
- //
- // R_390_TLS_GDCALL / R_390_TLS_LDCALL: marker relocation
- // R_390_PLT32DBL: __tls_get_offset
- //
- // After the relaxation we no longer call __tls_get_offset and should skip
- // both relocations to not create a false dependence on __tls_get_offset
- // being defined.
- //
- // Note that this mechanism only works correctly if the R_390_TLS_[GL]DCALL
- // is seen immediately *before* the R_390_PLT32DBL. Unfortunately, current
- // compilers on the platform will typically generate the inverse sequence.
- // To fix this, we sort relocations by offset in RelocationScanner::scan;
- // this ensures the correct sequence as the R_390_TLS_[GL]DCALL applies to
- // the first byte of the brasl instruction, while the R_390_PLT32DBL applies
- // to its third byte (the relative displacement).
-
- if (type == R_390_TLS_GDCALL || type == R_390_TLS_LDCALL)
- return 2;
- return 1;
-}
+ // Absolute relocations:
+ case R_390_8:
+ case R_390_12:
+ case R_390_16:
+ case R_390_20:
+ case R_390_32:
+ case R_390_64:
+ expr = R_ABS;
+ break;
+
+ // PC-relative relocations:
+ case R_390_PC16:
+ case R_390_PC32:
+ case R_390_PC64:
+ case R_390_PC12DBL:
+ case R_390_PC16DBL:
+ case R_390_PC24DBL:
+ case R_390_PC32DBL:
+ rs.processR_PC(type, offset, addend, sym);
+ continue;
-void SystemZ::relaxTlsGdToIe(uint8_t *loc, const Relocation &rel,
- uint64_t val) const {
- // The general-dynamic code sequence for a global `x`:
- //
- // Instruction Relocation Symbol
- // ear %rX,%a0
- // sllg %rX,%rX,32
- // ear %rX,%a1
- // larl %r12,_GLOBAL_OFFSET_TABLE_ R_390_GOTPCDBL _GLOBAL_OFFSET_TABLE_
- // lgrl %r2,.LC0 R_390_PC32DBL .LC0
- // brasl %r14,__tls_get_offset at plt R_390_TLS_GDCALL x
- // :tls_gdcall:x R_390_PLT32DBL __tls_get_offset
- // la %r2,0(%r2,%rX)
- //
- // .LC0:
- // .quad x at TLSGD R_390_TLS_GD64 x
- //
- // Relaxing to initial-exec entails:
- // 1) Replacing the call by a load from the GOT.
- // 2) Replacing the relocation on the constant LC0 by R_390_TLS_GOTIE64.
+ // PLT-generating relocations:
+ case R_390_PLT32:
+ case R_390_PLT64:
+ case R_390_PLT12DBL:
+ case R_390_PLT16DBL:
+ case R_390_PLT24DBL:
+ case R_390_PLT32DBL:
+ rs.processR_PLT_PC(type, offset, addend, sym);
+ continue;
+ case R_390_PLTOFF16:
+ case R_390_PLTOFF32:
+ case R_390_PLTOFF64:
+ expr = R_PLT_GOTREL;
+ break;
+
+ // GOT-generating relocations:
+ case R_390_GOTOFF16:
+ case R_390_GOTOFF: // a.k.a. R_390_GOTOFF32
+ case R_390_GOTOFF64:
+ ctx.in.got->hasGotOffRel.store(true, std::memory_order_relaxed);
+ expr = R_GOTREL;
+ break;
+ case R_390_GOTENT:
+ expr = R_GOT_PC;
+ break;
+ case R_390_GOT12:
+ case R_390_GOT16:
+ case R_390_GOT20:
+ case R_390_GOT32:
+ case R_390_GOT64:
+ expr = R_GOT_OFF;
+ break;
+
+ case R_390_GOTPLTENT:
+ expr = R_GOTPLT_PC;
+ break;
+ case R_390_GOTPLT12:
+ case R_390_GOTPLT16:
+ case R_390_GOTPLT20:
+ case R_390_GOTPLT32:
+ case R_390_GOTPLT64:
+ expr = R_GOTPLT_GOTREL;
+ break;
+ case R_390_GOTPC:
+ case R_390_GOTPCDBL:
+ ctx.in.got->hasGotOffRel.store(true, std::memory_order_relaxed);
+ expr = R_GOTONLY_PC;
+ break;
+
+ // TLS relocations:
+ case R_390_TLS_LE32:
+ case R_390_TLS_LE64:
+ if (rs.checkTlsLe(offset, sym, type))
+ continue;
+ expr = R_TPREL;
+ break;
+ case R_390_TLS_IE32:
+ case R_390_TLS_IE64:
+ // There is no IE to LE optimization.
+ sym.setFlags(NEEDS_TLSIE);
+ // R_GOT (absolute GOT address) needs a RELATIVE dynamic relocation
+ // in PIC.
+ if (ctx.arg.isPic)
+ sec.getPartition(ctx).relaDyn->addRelativeReloc(
+ ctx.target->relativeRel, sec, offset, sym, addend, type, R_GOT);
----------------
MaskRay wrote:
I'll move the ` template <bool enableIeToLe = true> void handleTlsIe` change from #181596 to this patch so that we can use `handleTlsIe<false>` here.
https://github.com/llvm/llvm-project/pull/181563
More information about the llvm-commits
mailing list