[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