Index: lld/ELF/Relocations.cpp
--- lld/ELF/Relocations.cpp.orig
+++ lld/ELF/Relocations.cpp
@@ -56,6 +56,29 @@ static void printDefinedLocation(ELFSyncStream &s, con
   s << "\n>>> defined in " << sym.file;
 }
 
+void elf::reportGNUWarning(Ctx &ctx, Symbol &sym, InputSectionBase &sec,
+                                 uint64_t offset) {
+  std::lock_guard<std::mutex> lock(ctx.relocMutex);
+  if (sym.gwarn) {
+    StringRef gnuWarning = gnuWarnings.lookup(sym.getName());
+    ELFSyncStream msg(ctx, DiagLevel::None);
+    // report first occurance only
+    sym.gwarn = false;
+    if (!gnuWarning.empty()) {
+      msg << sec.getSrcMsg(sym, offset);
+      msg << "(";
+      msg << sec.getObjMsg(offset);
+      msg << "): warning: ";
+      msg << gnuWarning;
+#if 0
+      warn(sec.getSrcMsg(sym, offset) + "(" + sec.getObjMsg(offset) +
+           "): warning: " + gnuWarning);
+#endif
+      Warn(ctx) << msg.str();
+    }
+  }
+}
+
 // Construct a message in the following format.
 //
 // >>> defined in /home/alice/src/foo.o
@@ -146,8 +169,8 @@ bool lld::elf::needsGot(RelExpr expr) {
 // file (PC, or GOT for example).
 static bool isRelExpr(RelExpr expr) {
   return oneof<R_PC, R_GOTREL, R_GOTPLTREL, RE_ARM_PCA, RE_MIPS_GOTREL,
-               RE_PPC64_CALL, RE_AARCH64_PAGE_PC, R_RELAX_GOT_PC,
-               RE_RISCV_PC_INDIRECT, RE_LOONGARCH_PAGE_PC,
+               RE_PPC64_CALL, RE_AARCH64_PAGE_PC, R_RELAX_GOT_OFF,
+               R_RELAX_GOT_PC, RE_RISCV_PC_INDIRECT, RE_LOONGARCH_PAGE_PC,
                RE_LOONGARCH_PC_INDIRECT>(expr);
 }
 
@@ -682,6 +705,13 @@ bool RelocScan::maybeReportUndefined(Undefined &sym, u
   if (sym.discardedSecIdx != 0 && (sec->name == ".got2" || sec->name == ".toc"))
     return false;
 
+#ifdef __OpenBSD__
+  // GCC (at least 8 and 11) can produce a ".gcc_except_table" with relocations
+  // to discarded sections on riscv64
+  if (sym.discardedSecIdx != 0 && sec->name == ".gcc_except_table")
+    return false;
+#endif
+
   bool isWarning =
       (ctx.arg.unresolvedSymbols == UnresolvedPolicy::Warn && canBeExternal) ||
       ctx.arg.noinhibitExec;
@@ -749,14 +779,18 @@ static void addRelativeReloc(Ctx &ctx, InputSectionBas
 template <class PltSection, class GotPltSection>
 static void addPltEntry(Ctx &ctx, PltSection &plt, GotPltSection &gotPlt,
                         RelocationBaseSection &rel, RelType type, Symbol &sym) {
+  RelExpr expr = sym.isPreemptible ? R_ADDEND : R_ABS;
   plt.addEntry(sym);
-  gotPlt.addEntry(sym);
-  if (sym.isPreemptible)
+  if (ctx.target->usesGotPlt) {
+    gotPlt.addEntry(sym);
+    // The relocation is applied to the .got.plt entry.
+    rel.addReloc({type, &gotPlt, sym.getGotPltOffset(ctx), !!sym.isPreemptible,
+                  sym, 0, expr});
+  } else {
+    // The relocation is applied to the .plt entry.
     rel.addReloc(
-        {type, &gotPlt, sym.getGotPltOffset(ctx), true, sym, 0, R_ADDEND});
-  else
-    rel.addReloc(
-        {type, &gotPlt, sym.getGotPltOffset(ctx), false, sym, 0, R_ABS});
+        {type, &plt, sym.getPltOffset(ctx), !!sym.isPreemptible, sym, 0, expr});
+  }
 }
 
 void elf::addGotEntry(Ctx &ctx, Symbol &sym) {
@@ -922,14 +956,19 @@ void RelocScan::process(RelExpr expr, RelType type, ui
   // indirection.
   const bool isIfunc = sym.isGnuIFunc();
   if (!sym.isPreemptible && !isIfunc) {
-    if (expr != R_GOT_PC) {
+    if (expr != R_GOT_PC && expr != R_GOT_OFF) {
       expr = fromPlt(expr);
     } else if (!isAbsoluteOrTls(sym)) {
-      expr = ctx.target->adjustGotPcExpr(type, addend,
+      if (expr == R_GOT_PC)
+        expr = ctx.target->adjustGotPcExpr(type, addend,
                                          sec->content().data() + offset);
-      // If the target adjusted the expression to R_RELAX_GOT_PC, we may end up
+      else if (expr == R_GOT_OFF)
+        expr = ctx.target->adjustGotOffExpr(type, sym, addend,
+                                          sec->content().data() + offset);
+
+      // If the target adjusted the expression to R_RELAX_GOT_*, we may end up
       // needing the GOT if we can't relax everything.
-      if (expr == R_RELAX_GOT_PC)
+      if (expr == R_RELAX_GOT_PC || expr == R_RELAX_GOT_OFF)
         ctx.in.got->hasGotOffRel.store(true, std::memory_order_relaxed);
     }
   }
@@ -993,10 +1032,16 @@ void RelocScan::processAux(RelExpr expr, RelType type,
                     (isa<EhInputSection>(sec) && ctx.arg.emachine != EM_MIPS));
   if (canWrite) {
     RelType rel = ctx.target->getDynRel(type);
-    if (oneof<R_GOT, RE_LOONGARCH_GOT>(expr) ||
-        ((rel == ctx.target->symbolicRel ||
-          (ctx.arg.emachine == EM_AARCH64 && type == R_AARCH64_AUTH_ABS64)) &&
-         !sym.isPreemptible)) {
+    bool useRelative =
+        (rel == ctx.target->symbolicRel ||
+         (ctx.arg.emachine == EM_AARCH64 && type == R_AARCH64_AUTH_ABS64)) &&
+        !sym.isPreemptible;
+    if (ctx.arg.emachine == EM_SPARCV9 &&
+        (type == R_SPARC_16 || type == R_SPARC_32 || type == R_SPARC_64 ||
+         type == R_SPARC_UA16 || type == R_SPARC_UA32 ||
+         type == R_SPARC_UA64))
+      useRelative = false;
+    if (oneof<R_GOT, RE_LOONGARCH_GOT>(expr) || useRelative) {
       addRelativeReloc<true>(ctx, *sec, offset, sym, addend, expr, type, shard);
       return;
     }
@@ -1021,6 +1066,7 @@ void RelocScan::processAux(RelExpr expr, RelType type,
           return;
         }
       }
+      ctx.target->prepareDynamicReloc(rel, sym, *sec);
       ctx.in.relaDyn->addSymbolReloc(rel, *sec, offset, sym, addend, type);
 
       // MIPS ABI turns using of GOT and dynamic relocations inside out.
@@ -1317,10 +1363,7 @@ void elf::postScanRelocations(Ctx &ctx) {
       } else {
         assert(sym.isFunc() && sym.hasFlag(NEEDS_PLT));
         if (!sym.isDefined()) {
-          replaceWithDefined(ctx, sym, *ctx.in.plt,
-                             ctx.target->pltHeaderSize +
-                                 ctx.target->pltEntrySize * sym.getPltIdx(ctx),
-                             0);
+          replaceWithDefined(ctx, sym, *ctx.in.plt, sym.getPltOffset(ctx), 0);
           sym.setFlags(NEEDS_COPY);
           if (ctx.arg.emachine == EM_PPC) {
             // PPC32 canonical PLT entries are at the beginning of .glink
