Skip to content

MC: Emit symbols for R_X86_64_PLT32 relocation pointing to symbols with non-zero values. #138795

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

pcc
Copy link
Contributor

@pcc pcc commented May 7, 2025

In the following case:

.section .text.a,"ax",@progbits
jmp .Lfoo

.text
ret
.Lfoo:
ret

we previously emitted an R_X86_64_PLT32 relocation for the jmp
instruction pointing to the .text section symbol with an addend of
-3. This is invalid because the linker is technically allowed to place
a PLT or other thunk at the jmp target, resulting in an invalid branch
to the thunk address + 1. Fix that by forcing a symbol to be used if it
has a non-zero value.

Created using spr 1.3.6-beta.1
@llvmbot
Copy link
Member

llvmbot commented May 7, 2025

@llvm/pr-subscribers-backend-aarch64
@llvm/pr-subscribers-mc
@llvm/pr-subscribers-backend-loongarch
@llvm/pr-subscribers-backend-sparc

@llvm/pr-subscribers-backend-risc-v

Author: Peter Collingbourne (pcc)

Changes

In the following case:

.section .text.a,"ax",@progbits
jmp .Lfoo

.text
ret
.Lfoo:
ret

we previously emitted an R_X86_64_PLT32 relocation for the jmp
instruction pointing to the .text section symbol with an addend of
-3. This is invalid because the linker is technically allowed to place
a PLT or other thunk at the jmp target, resulting in an invalid branch
to the thunk address + 1. Fix that by forcing a symbol to be used if it
has a non-zero value.


Full diff: https://github.com/llvm/llvm-project/pull/138795.diff

17 Files Affected:

  • (modified) llvm/include/llvm/MC/MCELFObjectWriter.h (+2-1)
  • (modified) llvm/lib/MC/ELFObjectWriter.cpp (+1-1)
  • (modified) llvm/lib/MC/MCELFObjectTargetWriter.cpp (+2-1)
  • (modified) llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp (+4-2)
  • (modified) llvm/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp (+4-2)
  • (modified) llvm/lib/Target/CSKY/MCTargetDesc/CSKYELFObjectWriter.cpp (+4-2)
  • (modified) llvm/lib/Target/Lanai/MCTargetDesc/LanaiELFObjectWriter.cpp (+4-2)
  • (modified) llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFObjectWriter.cpp (+2-1)
  • (modified) llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp (+7-5)
  • (modified) llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp (+4-2)
  • (modified) llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp (+2-1)
  • (modified) llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp (+4-2)
  • (modified) llvm/lib/Target/SystemZ/MCTargetDesc/SystemZELFObjectWriter.cpp (+4-2)
  • (modified) llvm/lib/Target/VE/MCTargetDesc/VEELFObjectWriter.cpp (+4-2)
  • (modified) llvm/lib/Target/X86/MCTargetDesc/X86ELFObjectWriter.cpp (+7-3)
  • (modified) llvm/lib/Target/Xtensa/MCTargetDesc/XtensaELFObjectWriter.cpp (+4-2)
  • (added) llvm/test/MC/ELF/plt-temporary.s (+14)
diff --git a/llvm/include/llvm/MC/MCELFObjectWriter.h b/llvm/include/llvm/MC/MCELFObjectWriter.h
index f0f2dca4738e4..76a5ec6346770 100644
--- a/llvm/include/llvm/MC/MCELFObjectWriter.h
+++ b/llvm/include/llvm/MC/MCELFObjectWriter.h
@@ -88,7 +88,8 @@ class MCELFObjectTargetWriter : public MCObjectTargetWriter {
   virtual unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                                 const MCFixup &Fixup, bool IsPCRel) const = 0;
 
-  virtual bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+  virtual bool needsRelocateWithSymbol(const MCAssembler &Asm,
+                                       const MCValue &Val, const MCSymbol &Sym,
                                        unsigned Type) const;
 
   virtual void sortRelocs(const MCAssembler &Asm,
diff --git a/llvm/lib/MC/ELFObjectWriter.cpp b/llvm/lib/MC/ELFObjectWriter.cpp
index 5c39daef9c98d..264a56f0966eb 100644
--- a/llvm/lib/MC/ELFObjectWriter.cpp
+++ b/llvm/lib/MC/ELFObjectWriter.cpp
@@ -1303,7 +1303,7 @@ bool ELFObjectWriter::useSectionSymbol(const MCAssembler &Asm,
   if (Asm.isThumbFunc(Sym))
     return false;
 
-  return !TargetObjectWriter->needsRelocateWithSymbol(Val, *Sym, Type);
+  return !TargetObjectWriter->needsRelocateWithSymbol(Asm, Val, *Sym, Type);
 }
 
 bool ELFObjectWriter::checkRelocation(MCContext &Ctx, SMLoc Loc,
diff --git a/llvm/lib/MC/MCELFObjectTargetWriter.cpp b/llvm/lib/MC/MCELFObjectTargetWriter.cpp
index 49cca57d3aaa3..5cfac5ba093e7 100644
--- a/llvm/lib/MC/MCELFObjectTargetWriter.cpp
+++ b/llvm/lib/MC/MCELFObjectTargetWriter.cpp
@@ -17,7 +17,8 @@ MCELFObjectTargetWriter::MCELFObjectTargetWriter(bool Is64Bit_, uint8_t OSABI_,
     : OSABI(OSABI_), ABIVersion(ABIVersion_), EMachine(EMachine_),
       HasRelocationAddend(HasRelocationAddend_), Is64Bit(Is64Bit_) {}
 
-bool MCELFObjectTargetWriter::needsRelocateWithSymbol(const MCValue &,
+bool MCELFObjectTargetWriter::needsRelocateWithSymbol(const MCAssembler &,
+                                                      const MCValue &,
                                                       const MCSymbol &,
                                                       unsigned Type) const {
   return false;
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp
index 53acf7dd61054..20d63415e768e 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp
@@ -38,7 +38,8 @@ class AArch64ELFObjectWriter : public MCELFObjectTargetWriter {
 protected:
   unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                         const MCFixup &Fixup, bool IsPCRel) const override;
-  bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+  bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                               const MCSymbol &Sym,
                                unsigned Type) const override;
   bool IsILP32;
 };
@@ -534,7 +535,8 @@ unsigned AArch64ELFObjectWriter::getRelocType(MCContext &Ctx,
   llvm_unreachable("Unimplemented fixup -> relocation");
 }
 
-bool AArch64ELFObjectWriter::needsRelocateWithSymbol(const MCValue &Val,
+bool AArch64ELFObjectWriter::needsRelocateWithSymbol(const MCAssembler &Asm,
+                                                     const MCValue &Val,
                                                      const MCSymbol &,
                                                      unsigned) const {
   // For memory-tagged symbols, ensure that the relocation uses the symbol. For
diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp
index 9fb681611594a..0dd71d55616ef 100644
--- a/llvm/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp
+++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp
@@ -39,7 +39,8 @@ namespace {
     unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                           const MCFixup &Fixup, bool IsPCRel) const override;
 
-    bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+    bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                                 const MCSymbol &Sym,
                                  unsigned Type) const override;
   };
 
@@ -50,7 +51,8 @@ ARMELFObjectWriter::ARMELFObjectWriter(uint8_t OSABI)
                             ELF::EM_ARM,
                             /*HasRelocationAddend*/ false) {}
 
-bool ARMELFObjectWriter::needsRelocateWithSymbol(const MCValue &,
+bool ARMELFObjectWriter::needsRelocateWithSymbol(const MCAssembler &Asm,
+                                                 const MCValue &,
                                                  const MCSymbol &,
                                                  unsigned Type) const {
   // FIXME: This is extremely conservative. This really needs to use an
diff --git a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYELFObjectWriter.cpp b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYELFObjectWriter.cpp
index d424399ce6bc9..89df9d1b6bdce 100644
--- a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYELFObjectWriter.cpp
+++ b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYELFObjectWriter.cpp
@@ -29,7 +29,8 @@ class CSKYELFObjectWriter : public MCELFObjectTargetWriter {
 
   unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                         const MCFixup &Fixup, bool IsPCRel) const override;
-  bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+  bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                               const MCSymbol &Sym,
                                unsigned Type) const override;
 };
 
@@ -167,7 +168,8 @@ unsigned CSKYELFObjectWriter::getRelocType(MCContext &Ctx,
   }
 }
 
-bool CSKYELFObjectWriter::needsRelocateWithSymbol(const MCValue &V,
+bool CSKYELFObjectWriter::needsRelocateWithSymbol(const MCAssembler &Asm,
+                                                  const MCValue &V,
                                                   const MCSymbol &,
                                                   unsigned Type) const {
   switch (V.getSpecifier()) {
diff --git a/llvm/lib/Target/Lanai/MCTargetDesc/LanaiELFObjectWriter.cpp b/llvm/lib/Target/Lanai/MCTargetDesc/LanaiELFObjectWriter.cpp
index a21518e44116e..744c4427fbec6 100644
--- a/llvm/lib/Target/Lanai/MCTargetDesc/LanaiELFObjectWriter.cpp
+++ b/llvm/lib/Target/Lanai/MCTargetDesc/LanaiELFObjectWriter.cpp
@@ -26,7 +26,8 @@ class LanaiELFObjectWriter : public MCELFObjectTargetWriter {
 protected:
   unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                         const MCFixup &Fixup, bool IsPCRel) const override;
-  bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+  bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                               const MCSymbol &Sym,
                                unsigned Type) const override;
 };
 
@@ -72,7 +73,8 @@ unsigned LanaiELFObjectWriter::getRelocType(MCContext & /*Ctx*/,
   return Type;
 }
 
-bool LanaiELFObjectWriter::needsRelocateWithSymbol(const MCValue &,
+bool LanaiELFObjectWriter::needsRelocateWithSymbol(const MCAssembler &Asm,
+                                                   const MCValue &,
                                                    const MCSymbol &,
                                                    unsigned Type) const {
   switch (Type) {
diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFObjectWriter.cpp b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFObjectWriter.cpp
index 5b6ecc1e8bc1f..55e9eef6de94e 100644
--- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFObjectWriter.cpp
+++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFObjectWriter.cpp
@@ -26,7 +26,8 @@ class LoongArchELFObjectWriter : public MCELFObjectTargetWriter {
 
   ~LoongArchELFObjectWriter() override;
 
-  bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+  bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                               const MCSymbol &Sym,
                                unsigned Type) const override {
     return EnableRelax;
   }
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp
index 83073e4243414..acee6413a5651 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp
@@ -50,7 +50,8 @@ class MipsELFObjectWriter : public MCELFObjectTargetWriter {
 
   unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                         const MCFixup &Fixup, bool IsPCRel) const override;
-  bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+  bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                               const MCSymbol &Sym,
                                unsigned Type) const override;
   void sortRelocs(const MCAssembler &Asm,
                   std::vector<ELFRelocationEntry> &Relocs) override;
@@ -444,15 +445,16 @@ void MipsELFObjectWriter::sortRelocs(const MCAssembler &Asm,
     Relocs[CopyTo++] = R.R;
 }
 
-bool MipsELFObjectWriter::needsRelocateWithSymbol(const MCValue &Val,
+bool MipsELFObjectWriter::needsRelocateWithSymbol(const MCAssembler &Asm,
+                                                  const MCValue &Val,
                                                   const MCSymbol &Sym,
                                                   unsigned Type) const {
   // If it's a compound relocation for N64 then we need the relocation if any
   // sub-relocation needs it.
   if (!isUInt<8>(Type))
-    return needsRelocateWithSymbol(Val, Sym, Type & 0xff) ||
-           needsRelocateWithSymbol(Val, Sym, (Type >> 8) & 0xff) ||
-           needsRelocateWithSymbol(Val, Sym, (Type >> 16) & 0xff);
+    return needsRelocateWithSymbol(Asm, Val, Sym, Type & 0xff) ||
+           needsRelocateWithSymbol(Asm, Val, Sym, (Type >> 8) & 0xff) ||
+           needsRelocateWithSymbol(Asm, Val, Sym, (Type >> 16) & 0xff);
 
   switch (Type) {
   default:
diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp
index e58c361db3104..84204f389123b 100644
--- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp
+++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp
@@ -28,7 +28,8 @@ namespace {
     unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                           const MCFixup &Fixup, bool IsPCRel) const override;
 
-    bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+    bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                                 const MCSymbol &Sym,
                                  unsigned Type) const override;
   };
 }
@@ -488,7 +489,8 @@ unsigned PPCELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target,
   return Type;
 }
 
-bool PPCELFObjectWriter::needsRelocateWithSymbol(const MCValue &,
+bool PPCELFObjectWriter::needsRelocateWithSymbol(const MCAssembler &Asm,
+                                                 const MCValue &,
                                                  const MCSymbol &Sym,
                                                  unsigned Type) const {
   switch (Type) {
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp
index 35e75489794f7..01953c4247235 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp
@@ -27,7 +27,8 @@ class RISCVELFObjectWriter : public MCELFObjectTargetWriter {
 
   // Return true if the given relocation must be with a symbol rather than
   // section plus offset.
-  bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+  bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                               const MCSymbol &Sym,
                                unsigned Type) const override {
     // TODO: this is very conservative, update once RISC-V psABI requirements
     //       are clarified.
diff --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp b/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp
index f95e5ac1664e6..560423210dfa2 100644
--- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp
+++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp
@@ -33,7 +33,8 @@ namespace {
     unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                           const MCFixup &Fixup, bool IsPCRel) const override;
 
-    bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+    bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                                 const MCSymbol &Sym,
                                  unsigned Type) const override;
   };
 }
@@ -144,7 +145,8 @@ unsigned SparcELFObjectWriter::getRelocType(MCContext &Ctx,
   return ELF::R_SPARC_NONE;
 }
 
-bool SparcELFObjectWriter::needsRelocateWithSymbol(const MCValue &,
+bool SparcELFObjectWriter::needsRelocateWithSymbol(const MCAssembler &Asm,
+                                                   const MCValue &,
                                                    const MCSymbol &,
                                                    unsigned Type) const {
   switch (Type) {
diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZELFObjectWriter.cpp b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZELFObjectWriter.cpp
index ea9d42080b9ec..28d98ffc5c0e3 100644
--- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZELFObjectWriter.cpp
+++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZELFObjectWriter.cpp
@@ -34,7 +34,8 @@ class SystemZELFObjectWriter : public MCELFObjectTargetWriter {
   // Override MCELFObjectTargetWriter.
   unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                         const MCFixup &Fixup, bool IsPCRel) const override;
-  bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+  bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                               const MCSymbol &Sym,
                                unsigned Type) const override;
 };
 
@@ -215,7 +216,8 @@ unsigned SystemZELFObjectWriter::getRelocType(MCContext &Ctx,
   }
 }
 
-bool SystemZELFObjectWriter::needsRelocateWithSymbol(const MCValue &V,
+bool SystemZELFObjectWriter::needsRelocateWithSymbol(const MCAssembler &Asm,
+                                                     const MCValue &V,
                                                      const MCSymbol &Sym,
                                                      unsigned Type) const {
   switch (V.getSpecifier()) {
diff --git a/llvm/lib/Target/VE/MCTargetDesc/VEELFObjectWriter.cpp b/llvm/lib/Target/VE/MCTargetDesc/VEELFObjectWriter.cpp
index 5d0d18d86d3f8..71f1f85552536 100644
--- a/llvm/lib/Target/VE/MCTargetDesc/VEELFObjectWriter.cpp
+++ b/llvm/lib/Target/VE/MCTargetDesc/VEELFObjectWriter.cpp
@@ -32,7 +32,8 @@ class VEELFObjectWriter : public MCELFObjectTargetWriter {
   unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                         const MCFixup &Fixup, bool IsPCRel) const override;
 
-  bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+  bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                               const MCSymbol &Sym,
                                unsigned Type) const override;
 };
 } // namespace
@@ -146,7 +147,8 @@ unsigned VEELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target,
   return ELF::R_VE_NONE;
 }
 
-bool VEELFObjectWriter::needsRelocateWithSymbol(const MCValue &,
+bool VEELFObjectWriter::needsRelocateWithSymbol(const MCAssembler &Asm,
+                                                const MCValue &,
                                                 const MCSymbol &,
                                                 unsigned Type) const {
   switch (Type) {
diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86ELFObjectWriter.cpp b/llvm/lib/Target/X86/MCTargetDesc/X86ELFObjectWriter.cpp
index cac4b81429b00..537536619d148 100644
--- a/llvm/lib/Target/X86/MCTargetDesc/X86ELFObjectWriter.cpp
+++ b/llvm/lib/Target/X86/MCTargetDesc/X86ELFObjectWriter.cpp
@@ -11,6 +11,7 @@
 #include "MCTargetDesc/X86MCTargetDesc.h"
 #include "llvm/BinaryFormat/ELF.h"
 #include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCAssembler.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCELFObjectWriter.h"
 #include "llvm/MC/MCExpr.h"
@@ -33,7 +34,8 @@ class X86ELFObjectWriter : public MCELFObjectTargetWriter {
 protected:
   unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                         const MCFixup &Fixup, bool IsPCRel) const override;
-  bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+  bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                               const MCSymbol &Sym,
                                unsigned Type) const override;
 };
 
@@ -386,7 +388,8 @@ unsigned X86ELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target,
   return getRelocType32(Ctx, Fixup.getLoc(), Specifier, RelType, IsPCRel, Kind);
 }
 
-bool X86ELFObjectWriter::needsRelocateWithSymbol(const MCValue &V,
+bool X86ELFObjectWriter::needsRelocateWithSymbol(const MCAssembler &Asm,
+                                                 const MCValue &V,
                                                  const MCSymbol &Sym,
                                                  unsigned Type) const {
   switch (V.getSpecifier()) {
@@ -396,7 +399,8 @@ bool X86ELFObjectWriter::needsRelocateWithSymbol(const MCValue &V,
   case X86MCExpr::VK_GOTPCREL_NORELAX:
     return true;
   default:
-    return false;
+    return Type == ELF::R_X86_64_PLT32 &&
+           (Asm.getFragmentOffset(*Sym.getFragment()) + Sym.getOffset()) != 0;
   }
 }
 
diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaELFObjectWriter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaELFObjectWriter.cpp
index 7472371932f11..635cfa206bc1f 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaELFObjectWriter.cpp
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaELFObjectWriter.cpp
@@ -32,7 +32,8 @@ class XtensaObjectWriter : public MCELFObjectTargetWriter {
 protected:
   unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                         const MCFixup &Fixup, bool IsPCRel) const override;
-  bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+  bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                               const MCSymbol &Sym,
                                unsigned Type) const override;
 };
 } // namespace
@@ -60,7 +61,8 @@ llvm::createXtensaObjectWriter(uint8_t OSABI, bool IsLittleEndian) {
   return std::make_unique<XtensaObjectWriter>(OSABI);
 }
 
-bool XtensaObjectWriter::needsRelocateWithSymbol(const MCValue &,
+bool XtensaObjectWriter::needsRelocateWithSymbol(const MCAssembler &Asm,
+                                                 const MCValue &,
                                                  const MCSymbol &,
                                                  unsigned Type) const {
   return false;
diff --git a/llvm/test/MC/ELF/plt-temporary.s b/llvm/test/MC/ELF/plt-temporary.s
new file mode 100644
index 0000000000000..9749bbdfe8134
--- /dev/null
+++ b/llvm/test/MC/ELF/plt-temporary.s
@@ -0,0 +1,14 @@
+// RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o - | llvm-readobj -r - | FileCheck %s
+
+// Test that this produces a R_X86_64_PLT32 pointing to .Lfoo
+// instead of the section symbol.
+
+.section .text.a,"ax",@progbits
+jmp .Lfoo
+
+.text
+ret
+.Lfoo:
+ret
+
+// CHECK: R_X86_64_PLT32 .Lfoo 0xFFFFFFFFFFFFFFFC

@llvmbot
Copy link
Member

llvmbot commented May 7, 2025

@llvm/pr-subscribers-backend-arm

Author: Peter Collingbourne (pcc)

Changes

In the following case:

.section .text.a,"ax",@progbits
jmp .Lfoo

.text
ret
.Lfoo:
ret

we previously emitted an R_X86_64_PLT32 relocation for the jmp
instruction pointing to the .text section symbol with an addend of
-3. This is invalid because the linker is technically allowed to place
a PLT or other thunk at the jmp target, resulting in an invalid branch
to the thunk address + 1. Fix that by forcing a symbol to be used if it
has a non-zero value.


Full diff: https://github.com/llvm/llvm-project/pull/138795.diff

17 Files Affected:

  • (modified) llvm/include/llvm/MC/MCELFObjectWriter.h (+2-1)
  • (modified) llvm/lib/MC/ELFObjectWriter.cpp (+1-1)
  • (modified) llvm/lib/MC/MCELFObjectTargetWriter.cpp (+2-1)
  • (modified) llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp (+4-2)
  • (modified) llvm/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp (+4-2)
  • (modified) llvm/lib/Target/CSKY/MCTargetDesc/CSKYELFObjectWriter.cpp (+4-2)
  • (modified) llvm/lib/Target/Lanai/MCTargetDesc/LanaiELFObjectWriter.cpp (+4-2)
  • (modified) llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFObjectWriter.cpp (+2-1)
  • (modified) llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp (+7-5)
  • (modified) llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp (+4-2)
  • (modified) llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp (+2-1)
  • (modified) llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp (+4-2)
  • (modified) llvm/lib/Target/SystemZ/MCTargetDesc/SystemZELFObjectWriter.cpp (+4-2)
  • (modified) llvm/lib/Target/VE/MCTargetDesc/VEELFObjectWriter.cpp (+4-2)
  • (modified) llvm/lib/Target/X86/MCTargetDesc/X86ELFObjectWriter.cpp (+7-3)
  • (modified) llvm/lib/Target/Xtensa/MCTargetDesc/XtensaELFObjectWriter.cpp (+4-2)
  • (added) llvm/test/MC/ELF/plt-temporary.s (+14)
diff --git a/llvm/include/llvm/MC/MCELFObjectWriter.h b/llvm/include/llvm/MC/MCELFObjectWriter.h
index f0f2dca4738e4..76a5ec6346770 100644
--- a/llvm/include/llvm/MC/MCELFObjectWriter.h
+++ b/llvm/include/llvm/MC/MCELFObjectWriter.h
@@ -88,7 +88,8 @@ class MCELFObjectTargetWriter : public MCObjectTargetWriter {
   virtual unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                                 const MCFixup &Fixup, bool IsPCRel) const = 0;
 
-  virtual bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+  virtual bool needsRelocateWithSymbol(const MCAssembler &Asm,
+                                       const MCValue &Val, const MCSymbol &Sym,
                                        unsigned Type) const;
 
   virtual void sortRelocs(const MCAssembler &Asm,
diff --git a/llvm/lib/MC/ELFObjectWriter.cpp b/llvm/lib/MC/ELFObjectWriter.cpp
index 5c39daef9c98d..264a56f0966eb 100644
--- a/llvm/lib/MC/ELFObjectWriter.cpp
+++ b/llvm/lib/MC/ELFObjectWriter.cpp
@@ -1303,7 +1303,7 @@ bool ELFObjectWriter::useSectionSymbol(const MCAssembler &Asm,
   if (Asm.isThumbFunc(Sym))
     return false;
 
-  return !TargetObjectWriter->needsRelocateWithSymbol(Val, *Sym, Type);
+  return !TargetObjectWriter->needsRelocateWithSymbol(Asm, Val, *Sym, Type);
 }
 
 bool ELFObjectWriter::checkRelocation(MCContext &Ctx, SMLoc Loc,
diff --git a/llvm/lib/MC/MCELFObjectTargetWriter.cpp b/llvm/lib/MC/MCELFObjectTargetWriter.cpp
index 49cca57d3aaa3..5cfac5ba093e7 100644
--- a/llvm/lib/MC/MCELFObjectTargetWriter.cpp
+++ b/llvm/lib/MC/MCELFObjectTargetWriter.cpp
@@ -17,7 +17,8 @@ MCELFObjectTargetWriter::MCELFObjectTargetWriter(bool Is64Bit_, uint8_t OSABI_,
     : OSABI(OSABI_), ABIVersion(ABIVersion_), EMachine(EMachine_),
       HasRelocationAddend(HasRelocationAddend_), Is64Bit(Is64Bit_) {}
 
-bool MCELFObjectTargetWriter::needsRelocateWithSymbol(const MCValue &,
+bool MCELFObjectTargetWriter::needsRelocateWithSymbol(const MCAssembler &,
+                                                      const MCValue &,
                                                       const MCSymbol &,
                                                       unsigned Type) const {
   return false;
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp
index 53acf7dd61054..20d63415e768e 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp
@@ -38,7 +38,8 @@ class AArch64ELFObjectWriter : public MCELFObjectTargetWriter {
 protected:
   unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                         const MCFixup &Fixup, bool IsPCRel) const override;
-  bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+  bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                               const MCSymbol &Sym,
                                unsigned Type) const override;
   bool IsILP32;
 };
@@ -534,7 +535,8 @@ unsigned AArch64ELFObjectWriter::getRelocType(MCContext &Ctx,
   llvm_unreachable("Unimplemented fixup -> relocation");
 }
 
-bool AArch64ELFObjectWriter::needsRelocateWithSymbol(const MCValue &Val,
+bool AArch64ELFObjectWriter::needsRelocateWithSymbol(const MCAssembler &Asm,
+                                                     const MCValue &Val,
                                                      const MCSymbol &,
                                                      unsigned) const {
   // For memory-tagged symbols, ensure that the relocation uses the symbol. For
diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp
index 9fb681611594a..0dd71d55616ef 100644
--- a/llvm/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp
+++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp
@@ -39,7 +39,8 @@ namespace {
     unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                           const MCFixup &Fixup, bool IsPCRel) const override;
 
-    bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+    bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                                 const MCSymbol &Sym,
                                  unsigned Type) const override;
   };
 
@@ -50,7 +51,8 @@ ARMELFObjectWriter::ARMELFObjectWriter(uint8_t OSABI)
                             ELF::EM_ARM,
                             /*HasRelocationAddend*/ false) {}
 
-bool ARMELFObjectWriter::needsRelocateWithSymbol(const MCValue &,
+bool ARMELFObjectWriter::needsRelocateWithSymbol(const MCAssembler &Asm,
+                                                 const MCValue &,
                                                  const MCSymbol &,
                                                  unsigned Type) const {
   // FIXME: This is extremely conservative. This really needs to use an
diff --git a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYELFObjectWriter.cpp b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYELFObjectWriter.cpp
index d424399ce6bc9..89df9d1b6bdce 100644
--- a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYELFObjectWriter.cpp
+++ b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYELFObjectWriter.cpp
@@ -29,7 +29,8 @@ class CSKYELFObjectWriter : public MCELFObjectTargetWriter {
 
   unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                         const MCFixup &Fixup, bool IsPCRel) const override;
-  bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+  bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                               const MCSymbol &Sym,
                                unsigned Type) const override;
 };
 
@@ -167,7 +168,8 @@ unsigned CSKYELFObjectWriter::getRelocType(MCContext &Ctx,
   }
 }
 
-bool CSKYELFObjectWriter::needsRelocateWithSymbol(const MCValue &V,
+bool CSKYELFObjectWriter::needsRelocateWithSymbol(const MCAssembler &Asm,
+                                                  const MCValue &V,
                                                   const MCSymbol &,
                                                   unsigned Type) const {
   switch (V.getSpecifier()) {
diff --git a/llvm/lib/Target/Lanai/MCTargetDesc/LanaiELFObjectWriter.cpp b/llvm/lib/Target/Lanai/MCTargetDesc/LanaiELFObjectWriter.cpp
index a21518e44116e..744c4427fbec6 100644
--- a/llvm/lib/Target/Lanai/MCTargetDesc/LanaiELFObjectWriter.cpp
+++ b/llvm/lib/Target/Lanai/MCTargetDesc/LanaiELFObjectWriter.cpp
@@ -26,7 +26,8 @@ class LanaiELFObjectWriter : public MCELFObjectTargetWriter {
 protected:
   unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                         const MCFixup &Fixup, bool IsPCRel) const override;
-  bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+  bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                               const MCSymbol &Sym,
                                unsigned Type) const override;
 };
 
@@ -72,7 +73,8 @@ unsigned LanaiELFObjectWriter::getRelocType(MCContext & /*Ctx*/,
   return Type;
 }
 
-bool LanaiELFObjectWriter::needsRelocateWithSymbol(const MCValue &,
+bool LanaiELFObjectWriter::needsRelocateWithSymbol(const MCAssembler &Asm,
+                                                   const MCValue &,
                                                    const MCSymbol &,
                                                    unsigned Type) const {
   switch (Type) {
diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFObjectWriter.cpp b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFObjectWriter.cpp
index 5b6ecc1e8bc1f..55e9eef6de94e 100644
--- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFObjectWriter.cpp
+++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFObjectWriter.cpp
@@ -26,7 +26,8 @@ class LoongArchELFObjectWriter : public MCELFObjectTargetWriter {
 
   ~LoongArchELFObjectWriter() override;
 
-  bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+  bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                               const MCSymbol &Sym,
                                unsigned Type) const override {
     return EnableRelax;
   }
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp
index 83073e4243414..acee6413a5651 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp
@@ -50,7 +50,8 @@ class MipsELFObjectWriter : public MCELFObjectTargetWriter {
 
   unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                         const MCFixup &Fixup, bool IsPCRel) const override;
-  bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+  bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                               const MCSymbol &Sym,
                                unsigned Type) const override;
   void sortRelocs(const MCAssembler &Asm,
                   std::vector<ELFRelocationEntry> &Relocs) override;
@@ -444,15 +445,16 @@ void MipsELFObjectWriter::sortRelocs(const MCAssembler &Asm,
     Relocs[CopyTo++] = R.R;
 }
 
-bool MipsELFObjectWriter::needsRelocateWithSymbol(const MCValue &Val,
+bool MipsELFObjectWriter::needsRelocateWithSymbol(const MCAssembler &Asm,
+                                                  const MCValue &Val,
                                                   const MCSymbol &Sym,
                                                   unsigned Type) const {
   // If it's a compound relocation for N64 then we need the relocation if any
   // sub-relocation needs it.
   if (!isUInt<8>(Type))
-    return needsRelocateWithSymbol(Val, Sym, Type & 0xff) ||
-           needsRelocateWithSymbol(Val, Sym, (Type >> 8) & 0xff) ||
-           needsRelocateWithSymbol(Val, Sym, (Type >> 16) & 0xff);
+    return needsRelocateWithSymbol(Asm, Val, Sym, Type & 0xff) ||
+           needsRelocateWithSymbol(Asm, Val, Sym, (Type >> 8) & 0xff) ||
+           needsRelocateWithSymbol(Asm, Val, Sym, (Type >> 16) & 0xff);
 
   switch (Type) {
   default:
diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp
index e58c361db3104..84204f389123b 100644
--- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp
+++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp
@@ -28,7 +28,8 @@ namespace {
     unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                           const MCFixup &Fixup, bool IsPCRel) const override;
 
-    bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+    bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                                 const MCSymbol &Sym,
                                  unsigned Type) const override;
   };
 }
@@ -488,7 +489,8 @@ unsigned PPCELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target,
   return Type;
 }
 
-bool PPCELFObjectWriter::needsRelocateWithSymbol(const MCValue &,
+bool PPCELFObjectWriter::needsRelocateWithSymbol(const MCAssembler &Asm,
+                                                 const MCValue &,
                                                  const MCSymbol &Sym,
                                                  unsigned Type) const {
   switch (Type) {
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp
index 35e75489794f7..01953c4247235 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp
@@ -27,7 +27,8 @@ class RISCVELFObjectWriter : public MCELFObjectTargetWriter {
 
   // Return true if the given relocation must be with a symbol rather than
   // section plus offset.
-  bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+  bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                               const MCSymbol &Sym,
                                unsigned Type) const override {
     // TODO: this is very conservative, update once RISC-V psABI requirements
     //       are clarified.
diff --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp b/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp
index f95e5ac1664e6..560423210dfa2 100644
--- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp
+++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp
@@ -33,7 +33,8 @@ namespace {
     unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                           const MCFixup &Fixup, bool IsPCRel) const override;
 
-    bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+    bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                                 const MCSymbol &Sym,
                                  unsigned Type) const override;
   };
 }
@@ -144,7 +145,8 @@ unsigned SparcELFObjectWriter::getRelocType(MCContext &Ctx,
   return ELF::R_SPARC_NONE;
 }
 
-bool SparcELFObjectWriter::needsRelocateWithSymbol(const MCValue &,
+bool SparcELFObjectWriter::needsRelocateWithSymbol(const MCAssembler &Asm,
+                                                   const MCValue &,
                                                    const MCSymbol &,
                                                    unsigned Type) const {
   switch (Type) {
diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZELFObjectWriter.cpp b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZELFObjectWriter.cpp
index ea9d42080b9ec..28d98ffc5c0e3 100644
--- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZELFObjectWriter.cpp
+++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZELFObjectWriter.cpp
@@ -34,7 +34,8 @@ class SystemZELFObjectWriter : public MCELFObjectTargetWriter {
   // Override MCELFObjectTargetWriter.
   unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                         const MCFixup &Fixup, bool IsPCRel) const override;
-  bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+  bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                               const MCSymbol &Sym,
                                unsigned Type) const override;
 };
 
@@ -215,7 +216,8 @@ unsigned SystemZELFObjectWriter::getRelocType(MCContext &Ctx,
   }
 }
 
-bool SystemZELFObjectWriter::needsRelocateWithSymbol(const MCValue &V,
+bool SystemZELFObjectWriter::needsRelocateWithSymbol(const MCAssembler &Asm,
+                                                     const MCValue &V,
                                                      const MCSymbol &Sym,
                                                      unsigned Type) const {
   switch (V.getSpecifier()) {
diff --git a/llvm/lib/Target/VE/MCTargetDesc/VEELFObjectWriter.cpp b/llvm/lib/Target/VE/MCTargetDesc/VEELFObjectWriter.cpp
index 5d0d18d86d3f8..71f1f85552536 100644
--- a/llvm/lib/Target/VE/MCTargetDesc/VEELFObjectWriter.cpp
+++ b/llvm/lib/Target/VE/MCTargetDesc/VEELFObjectWriter.cpp
@@ -32,7 +32,8 @@ class VEELFObjectWriter : public MCELFObjectTargetWriter {
   unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                         const MCFixup &Fixup, bool IsPCRel) const override;
 
-  bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+  bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                               const MCSymbol &Sym,
                                unsigned Type) const override;
 };
 } // namespace
@@ -146,7 +147,8 @@ unsigned VEELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target,
   return ELF::R_VE_NONE;
 }
 
-bool VEELFObjectWriter::needsRelocateWithSymbol(const MCValue &,
+bool VEELFObjectWriter::needsRelocateWithSymbol(const MCAssembler &Asm,
+                                                const MCValue &,
                                                 const MCSymbol &,
                                                 unsigned Type) const {
   switch (Type) {
diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86ELFObjectWriter.cpp b/llvm/lib/Target/X86/MCTargetDesc/X86ELFObjectWriter.cpp
index cac4b81429b00..537536619d148 100644
--- a/llvm/lib/Target/X86/MCTargetDesc/X86ELFObjectWriter.cpp
+++ b/llvm/lib/Target/X86/MCTargetDesc/X86ELFObjectWriter.cpp
@@ -11,6 +11,7 @@
 #include "MCTargetDesc/X86MCTargetDesc.h"
 #include "llvm/BinaryFormat/ELF.h"
 #include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCAssembler.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCELFObjectWriter.h"
 #include "llvm/MC/MCExpr.h"
@@ -33,7 +34,8 @@ class X86ELFObjectWriter : public MCELFObjectTargetWriter {
 protected:
   unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                         const MCFixup &Fixup, bool IsPCRel) const override;
-  bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+  bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                               const MCSymbol &Sym,
                                unsigned Type) const override;
 };
 
@@ -386,7 +388,8 @@ unsigned X86ELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target,
   return getRelocType32(Ctx, Fixup.getLoc(), Specifier, RelType, IsPCRel, Kind);
 }
 
-bool X86ELFObjectWriter::needsRelocateWithSymbol(const MCValue &V,
+bool X86ELFObjectWriter::needsRelocateWithSymbol(const MCAssembler &Asm,
+                                                 const MCValue &V,
                                                  const MCSymbol &Sym,
                                                  unsigned Type) const {
   switch (V.getSpecifier()) {
@@ -396,7 +399,8 @@ bool X86ELFObjectWriter::needsRelocateWithSymbol(const MCValue &V,
   case X86MCExpr::VK_GOTPCREL_NORELAX:
     return true;
   default:
-    return false;
+    return Type == ELF::R_X86_64_PLT32 &&
+           (Asm.getFragmentOffset(*Sym.getFragment()) + Sym.getOffset()) != 0;
   }
 }
 
diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaELFObjectWriter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaELFObjectWriter.cpp
index 7472371932f11..635cfa206bc1f 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaELFObjectWriter.cpp
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaELFObjectWriter.cpp
@@ -32,7 +32,8 @@ class XtensaObjectWriter : public MCELFObjectTargetWriter {
 protected:
   unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                         const MCFixup &Fixup, bool IsPCRel) const override;
-  bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+  bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                               const MCSymbol &Sym,
                                unsigned Type) const override;
 };
 } // namespace
@@ -60,7 +61,8 @@ llvm::createXtensaObjectWriter(uint8_t OSABI, bool IsLittleEndian) {
   return std::make_unique<XtensaObjectWriter>(OSABI);
 }
 
-bool XtensaObjectWriter::needsRelocateWithSymbol(const MCValue &,
+bool XtensaObjectWriter::needsRelocateWithSymbol(const MCAssembler &Asm,
+                                                 const MCValue &,
                                                  const MCSymbol &,
                                                  unsigned Type) const {
   return false;
diff --git a/llvm/test/MC/ELF/plt-temporary.s b/llvm/test/MC/ELF/plt-temporary.s
new file mode 100644
index 0000000000000..9749bbdfe8134
--- /dev/null
+++ b/llvm/test/MC/ELF/plt-temporary.s
@@ -0,0 +1,14 @@
+// RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o - | llvm-readobj -r - | FileCheck %s
+
+// Test that this produces a R_X86_64_PLT32 pointing to .Lfoo
+// instead of the section symbol.
+
+.section .text.a,"ax",@progbits
+jmp .Lfoo
+
+.text
+ret
+.Lfoo:
+ret
+
+// CHECK: R_X86_64_PLT32 .Lfoo 0xFFFFFFFFFFFFFFFC

@llvmbot
Copy link
Member

llvmbot commented May 7, 2025

@llvm/pr-subscribers-backend-xtensa

Author: Peter Collingbourne (pcc)

Changes

In the following case:

.section .text.a,"ax",@progbits
jmp .Lfoo

.text
ret
.Lfoo:
ret

we previously emitted an R_X86_64_PLT32 relocation for the jmp
instruction pointing to the .text section symbol with an addend of
-3. This is invalid because the linker is technically allowed to place
a PLT or other thunk at the jmp target, resulting in an invalid branch
to the thunk address + 1. Fix that by forcing a symbol to be used if it
has a non-zero value.


Full diff: https://github.com/llvm/llvm-project/pull/138795.diff

17 Files Affected:

  • (modified) llvm/include/llvm/MC/MCELFObjectWriter.h (+2-1)
  • (modified) llvm/lib/MC/ELFObjectWriter.cpp (+1-1)
  • (modified) llvm/lib/MC/MCELFObjectTargetWriter.cpp (+2-1)
  • (modified) llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp (+4-2)
  • (modified) llvm/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp (+4-2)
  • (modified) llvm/lib/Target/CSKY/MCTargetDesc/CSKYELFObjectWriter.cpp (+4-2)
  • (modified) llvm/lib/Target/Lanai/MCTargetDesc/LanaiELFObjectWriter.cpp (+4-2)
  • (modified) llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFObjectWriter.cpp (+2-1)
  • (modified) llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp (+7-5)
  • (modified) llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp (+4-2)
  • (modified) llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp (+2-1)
  • (modified) llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp (+4-2)
  • (modified) llvm/lib/Target/SystemZ/MCTargetDesc/SystemZELFObjectWriter.cpp (+4-2)
  • (modified) llvm/lib/Target/VE/MCTargetDesc/VEELFObjectWriter.cpp (+4-2)
  • (modified) llvm/lib/Target/X86/MCTargetDesc/X86ELFObjectWriter.cpp (+7-3)
  • (modified) llvm/lib/Target/Xtensa/MCTargetDesc/XtensaELFObjectWriter.cpp (+4-2)
  • (added) llvm/test/MC/ELF/plt-temporary.s (+14)
diff --git a/llvm/include/llvm/MC/MCELFObjectWriter.h b/llvm/include/llvm/MC/MCELFObjectWriter.h
index f0f2dca4738e4..76a5ec6346770 100644
--- a/llvm/include/llvm/MC/MCELFObjectWriter.h
+++ b/llvm/include/llvm/MC/MCELFObjectWriter.h
@@ -88,7 +88,8 @@ class MCELFObjectTargetWriter : public MCObjectTargetWriter {
   virtual unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                                 const MCFixup &Fixup, bool IsPCRel) const = 0;
 
-  virtual bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+  virtual bool needsRelocateWithSymbol(const MCAssembler &Asm,
+                                       const MCValue &Val, const MCSymbol &Sym,
                                        unsigned Type) const;
 
   virtual void sortRelocs(const MCAssembler &Asm,
diff --git a/llvm/lib/MC/ELFObjectWriter.cpp b/llvm/lib/MC/ELFObjectWriter.cpp
index 5c39daef9c98d..264a56f0966eb 100644
--- a/llvm/lib/MC/ELFObjectWriter.cpp
+++ b/llvm/lib/MC/ELFObjectWriter.cpp
@@ -1303,7 +1303,7 @@ bool ELFObjectWriter::useSectionSymbol(const MCAssembler &Asm,
   if (Asm.isThumbFunc(Sym))
     return false;
 
-  return !TargetObjectWriter->needsRelocateWithSymbol(Val, *Sym, Type);
+  return !TargetObjectWriter->needsRelocateWithSymbol(Asm, Val, *Sym, Type);
 }
 
 bool ELFObjectWriter::checkRelocation(MCContext &Ctx, SMLoc Loc,
diff --git a/llvm/lib/MC/MCELFObjectTargetWriter.cpp b/llvm/lib/MC/MCELFObjectTargetWriter.cpp
index 49cca57d3aaa3..5cfac5ba093e7 100644
--- a/llvm/lib/MC/MCELFObjectTargetWriter.cpp
+++ b/llvm/lib/MC/MCELFObjectTargetWriter.cpp
@@ -17,7 +17,8 @@ MCELFObjectTargetWriter::MCELFObjectTargetWriter(bool Is64Bit_, uint8_t OSABI_,
     : OSABI(OSABI_), ABIVersion(ABIVersion_), EMachine(EMachine_),
       HasRelocationAddend(HasRelocationAddend_), Is64Bit(Is64Bit_) {}
 
-bool MCELFObjectTargetWriter::needsRelocateWithSymbol(const MCValue &,
+bool MCELFObjectTargetWriter::needsRelocateWithSymbol(const MCAssembler &,
+                                                      const MCValue &,
                                                       const MCSymbol &,
                                                       unsigned Type) const {
   return false;
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp
index 53acf7dd61054..20d63415e768e 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp
@@ -38,7 +38,8 @@ class AArch64ELFObjectWriter : public MCELFObjectTargetWriter {
 protected:
   unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                         const MCFixup &Fixup, bool IsPCRel) const override;
-  bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+  bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                               const MCSymbol &Sym,
                                unsigned Type) const override;
   bool IsILP32;
 };
@@ -534,7 +535,8 @@ unsigned AArch64ELFObjectWriter::getRelocType(MCContext &Ctx,
   llvm_unreachable("Unimplemented fixup -> relocation");
 }
 
-bool AArch64ELFObjectWriter::needsRelocateWithSymbol(const MCValue &Val,
+bool AArch64ELFObjectWriter::needsRelocateWithSymbol(const MCAssembler &Asm,
+                                                     const MCValue &Val,
                                                      const MCSymbol &,
                                                      unsigned) const {
   // For memory-tagged symbols, ensure that the relocation uses the symbol. For
diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp
index 9fb681611594a..0dd71d55616ef 100644
--- a/llvm/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp
+++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp
@@ -39,7 +39,8 @@ namespace {
     unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                           const MCFixup &Fixup, bool IsPCRel) const override;
 
-    bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+    bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                                 const MCSymbol &Sym,
                                  unsigned Type) const override;
   };
 
@@ -50,7 +51,8 @@ ARMELFObjectWriter::ARMELFObjectWriter(uint8_t OSABI)
                             ELF::EM_ARM,
                             /*HasRelocationAddend*/ false) {}
 
-bool ARMELFObjectWriter::needsRelocateWithSymbol(const MCValue &,
+bool ARMELFObjectWriter::needsRelocateWithSymbol(const MCAssembler &Asm,
+                                                 const MCValue &,
                                                  const MCSymbol &,
                                                  unsigned Type) const {
   // FIXME: This is extremely conservative. This really needs to use an
diff --git a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYELFObjectWriter.cpp b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYELFObjectWriter.cpp
index d424399ce6bc9..89df9d1b6bdce 100644
--- a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYELFObjectWriter.cpp
+++ b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYELFObjectWriter.cpp
@@ -29,7 +29,8 @@ class CSKYELFObjectWriter : public MCELFObjectTargetWriter {
 
   unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                         const MCFixup &Fixup, bool IsPCRel) const override;
-  bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+  bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                               const MCSymbol &Sym,
                                unsigned Type) const override;
 };
 
@@ -167,7 +168,8 @@ unsigned CSKYELFObjectWriter::getRelocType(MCContext &Ctx,
   }
 }
 
-bool CSKYELFObjectWriter::needsRelocateWithSymbol(const MCValue &V,
+bool CSKYELFObjectWriter::needsRelocateWithSymbol(const MCAssembler &Asm,
+                                                  const MCValue &V,
                                                   const MCSymbol &,
                                                   unsigned Type) const {
   switch (V.getSpecifier()) {
diff --git a/llvm/lib/Target/Lanai/MCTargetDesc/LanaiELFObjectWriter.cpp b/llvm/lib/Target/Lanai/MCTargetDesc/LanaiELFObjectWriter.cpp
index a21518e44116e..744c4427fbec6 100644
--- a/llvm/lib/Target/Lanai/MCTargetDesc/LanaiELFObjectWriter.cpp
+++ b/llvm/lib/Target/Lanai/MCTargetDesc/LanaiELFObjectWriter.cpp
@@ -26,7 +26,8 @@ class LanaiELFObjectWriter : public MCELFObjectTargetWriter {
 protected:
   unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                         const MCFixup &Fixup, bool IsPCRel) const override;
-  bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+  bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                               const MCSymbol &Sym,
                                unsigned Type) const override;
 };
 
@@ -72,7 +73,8 @@ unsigned LanaiELFObjectWriter::getRelocType(MCContext & /*Ctx*/,
   return Type;
 }
 
-bool LanaiELFObjectWriter::needsRelocateWithSymbol(const MCValue &,
+bool LanaiELFObjectWriter::needsRelocateWithSymbol(const MCAssembler &Asm,
+                                                   const MCValue &,
                                                    const MCSymbol &,
                                                    unsigned Type) const {
   switch (Type) {
diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFObjectWriter.cpp b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFObjectWriter.cpp
index 5b6ecc1e8bc1f..55e9eef6de94e 100644
--- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFObjectWriter.cpp
+++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchELFObjectWriter.cpp
@@ -26,7 +26,8 @@ class LoongArchELFObjectWriter : public MCELFObjectTargetWriter {
 
   ~LoongArchELFObjectWriter() override;
 
-  bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+  bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                               const MCSymbol &Sym,
                                unsigned Type) const override {
     return EnableRelax;
   }
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp
index 83073e4243414..acee6413a5651 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp
@@ -50,7 +50,8 @@ class MipsELFObjectWriter : public MCELFObjectTargetWriter {
 
   unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                         const MCFixup &Fixup, bool IsPCRel) const override;
-  bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+  bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                               const MCSymbol &Sym,
                                unsigned Type) const override;
   void sortRelocs(const MCAssembler &Asm,
                   std::vector<ELFRelocationEntry> &Relocs) override;
@@ -444,15 +445,16 @@ void MipsELFObjectWriter::sortRelocs(const MCAssembler &Asm,
     Relocs[CopyTo++] = R.R;
 }
 
-bool MipsELFObjectWriter::needsRelocateWithSymbol(const MCValue &Val,
+bool MipsELFObjectWriter::needsRelocateWithSymbol(const MCAssembler &Asm,
+                                                  const MCValue &Val,
                                                   const MCSymbol &Sym,
                                                   unsigned Type) const {
   // If it's a compound relocation for N64 then we need the relocation if any
   // sub-relocation needs it.
   if (!isUInt<8>(Type))
-    return needsRelocateWithSymbol(Val, Sym, Type & 0xff) ||
-           needsRelocateWithSymbol(Val, Sym, (Type >> 8) & 0xff) ||
-           needsRelocateWithSymbol(Val, Sym, (Type >> 16) & 0xff);
+    return needsRelocateWithSymbol(Asm, Val, Sym, Type & 0xff) ||
+           needsRelocateWithSymbol(Asm, Val, Sym, (Type >> 8) & 0xff) ||
+           needsRelocateWithSymbol(Asm, Val, Sym, (Type >> 16) & 0xff);
 
   switch (Type) {
   default:
diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp
index e58c361db3104..84204f389123b 100644
--- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp
+++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp
@@ -28,7 +28,8 @@ namespace {
     unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                           const MCFixup &Fixup, bool IsPCRel) const override;
 
-    bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+    bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                                 const MCSymbol &Sym,
                                  unsigned Type) const override;
   };
 }
@@ -488,7 +489,8 @@ unsigned PPCELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target,
   return Type;
 }
 
-bool PPCELFObjectWriter::needsRelocateWithSymbol(const MCValue &,
+bool PPCELFObjectWriter::needsRelocateWithSymbol(const MCAssembler &Asm,
+                                                 const MCValue &,
                                                  const MCSymbol &Sym,
                                                  unsigned Type) const {
   switch (Type) {
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp
index 35e75489794f7..01953c4247235 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp
@@ -27,7 +27,8 @@ class RISCVELFObjectWriter : public MCELFObjectTargetWriter {
 
   // Return true if the given relocation must be with a symbol rather than
   // section plus offset.
-  bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+  bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                               const MCSymbol &Sym,
                                unsigned Type) const override {
     // TODO: this is very conservative, update once RISC-V psABI requirements
     //       are clarified.
diff --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp b/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp
index f95e5ac1664e6..560423210dfa2 100644
--- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp
+++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp
@@ -33,7 +33,8 @@ namespace {
     unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                           const MCFixup &Fixup, bool IsPCRel) const override;
 
-    bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+    bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                                 const MCSymbol &Sym,
                                  unsigned Type) const override;
   };
 }
@@ -144,7 +145,8 @@ unsigned SparcELFObjectWriter::getRelocType(MCContext &Ctx,
   return ELF::R_SPARC_NONE;
 }
 
-bool SparcELFObjectWriter::needsRelocateWithSymbol(const MCValue &,
+bool SparcELFObjectWriter::needsRelocateWithSymbol(const MCAssembler &Asm,
+                                                   const MCValue &,
                                                    const MCSymbol &,
                                                    unsigned Type) const {
   switch (Type) {
diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZELFObjectWriter.cpp b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZELFObjectWriter.cpp
index ea9d42080b9ec..28d98ffc5c0e3 100644
--- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZELFObjectWriter.cpp
+++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZELFObjectWriter.cpp
@@ -34,7 +34,8 @@ class SystemZELFObjectWriter : public MCELFObjectTargetWriter {
   // Override MCELFObjectTargetWriter.
   unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                         const MCFixup &Fixup, bool IsPCRel) const override;
-  bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+  bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                               const MCSymbol &Sym,
                                unsigned Type) const override;
 };
 
@@ -215,7 +216,8 @@ unsigned SystemZELFObjectWriter::getRelocType(MCContext &Ctx,
   }
 }
 
-bool SystemZELFObjectWriter::needsRelocateWithSymbol(const MCValue &V,
+bool SystemZELFObjectWriter::needsRelocateWithSymbol(const MCAssembler &Asm,
+                                                     const MCValue &V,
                                                      const MCSymbol &Sym,
                                                      unsigned Type) const {
   switch (V.getSpecifier()) {
diff --git a/llvm/lib/Target/VE/MCTargetDesc/VEELFObjectWriter.cpp b/llvm/lib/Target/VE/MCTargetDesc/VEELFObjectWriter.cpp
index 5d0d18d86d3f8..71f1f85552536 100644
--- a/llvm/lib/Target/VE/MCTargetDesc/VEELFObjectWriter.cpp
+++ b/llvm/lib/Target/VE/MCTargetDesc/VEELFObjectWriter.cpp
@@ -32,7 +32,8 @@ class VEELFObjectWriter : public MCELFObjectTargetWriter {
   unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                         const MCFixup &Fixup, bool IsPCRel) const override;
 
-  bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+  bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                               const MCSymbol &Sym,
                                unsigned Type) const override;
 };
 } // namespace
@@ -146,7 +147,8 @@ unsigned VEELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target,
   return ELF::R_VE_NONE;
 }
 
-bool VEELFObjectWriter::needsRelocateWithSymbol(const MCValue &,
+bool VEELFObjectWriter::needsRelocateWithSymbol(const MCAssembler &Asm,
+                                                const MCValue &,
                                                 const MCSymbol &,
                                                 unsigned Type) const {
   switch (Type) {
diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86ELFObjectWriter.cpp b/llvm/lib/Target/X86/MCTargetDesc/X86ELFObjectWriter.cpp
index cac4b81429b00..537536619d148 100644
--- a/llvm/lib/Target/X86/MCTargetDesc/X86ELFObjectWriter.cpp
+++ b/llvm/lib/Target/X86/MCTargetDesc/X86ELFObjectWriter.cpp
@@ -11,6 +11,7 @@
 #include "MCTargetDesc/X86MCTargetDesc.h"
 #include "llvm/BinaryFormat/ELF.h"
 #include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCAssembler.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCELFObjectWriter.h"
 #include "llvm/MC/MCExpr.h"
@@ -33,7 +34,8 @@ class X86ELFObjectWriter : public MCELFObjectTargetWriter {
 protected:
   unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                         const MCFixup &Fixup, bool IsPCRel) const override;
-  bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+  bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                               const MCSymbol &Sym,
                                unsigned Type) const override;
 };
 
@@ -386,7 +388,8 @@ unsigned X86ELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target,
   return getRelocType32(Ctx, Fixup.getLoc(), Specifier, RelType, IsPCRel, Kind);
 }
 
-bool X86ELFObjectWriter::needsRelocateWithSymbol(const MCValue &V,
+bool X86ELFObjectWriter::needsRelocateWithSymbol(const MCAssembler &Asm,
+                                                 const MCValue &V,
                                                  const MCSymbol &Sym,
                                                  unsigned Type) const {
   switch (V.getSpecifier()) {
@@ -396,7 +399,8 @@ bool X86ELFObjectWriter::needsRelocateWithSymbol(const MCValue &V,
   case X86MCExpr::VK_GOTPCREL_NORELAX:
     return true;
   default:
-    return false;
+    return Type == ELF::R_X86_64_PLT32 &&
+           (Asm.getFragmentOffset(*Sym.getFragment()) + Sym.getOffset()) != 0;
   }
 }
 
diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaELFObjectWriter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaELFObjectWriter.cpp
index 7472371932f11..635cfa206bc1f 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaELFObjectWriter.cpp
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaELFObjectWriter.cpp
@@ -32,7 +32,8 @@ class XtensaObjectWriter : public MCELFObjectTargetWriter {
 protected:
   unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                         const MCFixup &Fixup, bool IsPCRel) const override;
-  bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
+  bool needsRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
+                               const MCSymbol &Sym,
                                unsigned Type) const override;
 };
 } // namespace
@@ -60,7 +61,8 @@ llvm::createXtensaObjectWriter(uint8_t OSABI, bool IsLittleEndian) {
   return std::make_unique<XtensaObjectWriter>(OSABI);
 }
 
-bool XtensaObjectWriter::needsRelocateWithSymbol(const MCValue &,
+bool XtensaObjectWriter::needsRelocateWithSymbol(const MCAssembler &Asm,
+                                                 const MCValue &,
                                                  const MCSymbol &,
                                                  unsigned Type) const {
   return false;
diff --git a/llvm/test/MC/ELF/plt-temporary.s b/llvm/test/MC/ELF/plt-temporary.s
new file mode 100644
index 0000000000000..9749bbdfe8134
--- /dev/null
+++ b/llvm/test/MC/ELF/plt-temporary.s
@@ -0,0 +1,14 @@
+// RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o - | llvm-readobj -r - | FileCheck %s
+
+// Test that this produces a R_X86_64_PLT32 pointing to .Lfoo
+// instead of the section symbol.
+
+.section .text.a,"ax",@progbits
+jmp .Lfoo
+
+.text
+ret
+.Lfoo:
+ret
+
+// CHECK: R_X86_64_PLT32 .Lfoo 0xFFFFFFFFFFFFFFFC

Created using spr 1.3.6-beta.1
@MaskRay
Copy link
Member

MaskRay commented May 7, 2025

This is invalid because the linker is technically allowed to place a PLT or other thunk at the jmp target, resulting in an invalid branch to the thunk address + 1.

Why is it invalid? Can you elaborate the scenario when a PLT is placed at the jmp target?

@pcc
Copy link
Contributor Author

pcc commented May 7, 2025

I was thinking something like a range extension thunk (although those don't currently exist on x86), which could be useful for something like a medium code model that supports >2GB code. In that case, if your branch and target are on opposite ends of the output file which is possible e.g. if they are in different sections you would need a thunk.

The reason I wanted to fix this is that having these relocations breaks the branch-to-branch optimization as noted in #138366 (comment) .

@MaskRay
Copy link
Member

MaskRay commented May 7, 2025

I've read #138366 (comment) but I am still not following.
What is invalid?

Note that range extension thunks track both the symbol and the addend (e.g. https://reviews.llvm.org/D70637 (AArch64)).
So we could add a thunk for the R_X86_64_PLT32 relocation with a -3 offset.

@pcc
Copy link
Contributor Author

pcc commented May 7, 2025

With relative vtables we have

.4byte foo@plt - .

This becomes a PLT32 pointing to foo with addend 0. This should not be treated as a branch to foo+4 if a PLT/thunk is needed.

We can also have

.section .text.a,"ax",@progbits
jmp .Lfoo

.text
nop
nop
nop
nop
.Lfoo:
ret

With the current implementation that creates a PLT32 with addend 0 for branching to .text+4 this is not distinguishable from the relative vtable case except via SHF_EXECINSTR or STT_SECTION on the target symbol. Since we generally want relocation processing to be independent of this kind of context, I think the right way to reconcile these two cases is that a PLT32 can only be treated as a reference to the symbol itself. GNU as already does this and this change makes MC do the same.

@MaskRay
Copy link
Member

MaskRay commented May 7, 2025

The goal is to differentiate two scenarios when a symbol is referenced by a potential R_X86_64_PLT32 relocation:

  • .4byte foo@plt - . (LLVM assembly extension, not supported in GNU assembler): No redirection to a thunk. References foo or its PLT entry.
  • jmp foo; .section .text.foo,"ax"; .fill 4,1,0x90; foo: Redirect to a thunk if necessary to avoid displacement overflow.

When foo is local: in the .4byte case, Clang references foo, while in the jmp foo case, it references .text.foo.
When foo is a global or weak symbol, Clang references foo in both cases, making them indistinguishable to the linker.

(See https://sourceware.org/bugzilla/show_bug.cgi?id=26263 for gas behavior. I do not follow the argument "Since PLT32 relocation must be against symbols". I don't know whether it fixed an issue in GNU ld's i386 port for the 32-bit case.)

I am still confused as to what issues this PR attempts to resolve.

Current behavior:

jmp foo # llvm: PLT32(.text.foo); gas: PC32(.text.foo)
jmp goo # PLT(goo)

.section .text.foo,"ax"
.fill 1, 4, 0x90
.globl goo
foo:
goo:

.data
.4byte foo@plt - .  # foo
.4byte goo@plt - .  # goo

This PR changes jmp foo to PLT32(foo)

If we implement range extension thunks, we should support both PC32 and PLT32.
To disable range extension thunks for .4byte foo@plt - . (LLVM assembly extension), we should introduce a new relocation type.
(In RISC-V, instead of following x86 naming with R_RISCV_PLT32, R_RISCV_PLT32_PCREL would be preferable.)

@pcc
Copy link
Contributor Author

pcc commented May 7, 2025

Sorry, let me try again with the concrete problem that I was seeing and trying to solve.

With this .s file:

.section .text.a,"ax",@progbits
jmp foo

.section .text.b,"ax",@progbits
bar:
ret

.text
jmp bar
foo:
ret

and with an lld patched with #138366:

$ ra/bin/clang -c jmp2.s
$ ra/bin/ld.lld jmp2.o --branch-to-branch
ld.lld: warning: cannot find entry symbol _start; not setting start address
$ objdump -d

a.out:     file format elf64-x86-64


Disassembly of section .text:

0000000000201120 <foo-0x5>:
  201120:	e9 06 00 00 00       	jmp    20112b <bar>

0000000000201125 <foo>:
  201125:	c3                   	ret
  201126:	e9 05 00 00 00       	jmp    201130 <bar+0x5>

000000000020112b <bar>:
  20112b:	c3                   	ret

The instruction at 0x201126 is incorrect. This is because of the interpretation of jmp foo. Currently it is assembled as jmp .text+5 i.e. PLT32 with symbol .text and addend 1. With the current implementation of branch-to-branch this is treated as a branch to .text that needs 1 added to the operand (similar to the relative vtable case). Consequently it finds the relocation for jmp bar at the beginning of the section, assumes that is the target and incorrectly rewrites it.

After #138795 we have:

$ objdump -d

a.out:     file format elf64-x86-64


Disassembly of section .text:

0000000000201120 <foo-0x5>:
  201120:	e9 06 00 00 00       	jmp    20112b <bar>

0000000000201125 <foo>:
  201125:	c3                   	ret
  201126:	e9 fa ff ff ff       	jmp    201125 <foo>

000000000020112b <bar>:
  20112b:	c3                   	ret

The alternative fix, which I think I'm now leaning towards, would be to change how the branch-to-branch optimization handles relocations to STT_SECTION symbols. A relocation pointing to the STT_SECTION for .text with addend 1 would be treated as a branch to .text+5 and it would be invalid to assemble a relative vtable relocation that points to STT_SECTION. It would also be consistent with how we process relocations for string tail merging and ICF among other places, e.g. here. The downside is that it adds another special case for STT_SECTION but I guess that's fine.

@MaskRay
Copy link
Member

MaskRay commented May 8, 2025

The alternative fix, which I think I'm now leaning towards, would be to change how the branch-to-branch optimization handles relocations to STT_SECTION symbols. A relocation pointing to the STT_SECTION for .text with addend 1 would be treated as a branch to .text+5 and it would be invalid to assemble a relative vtable relocation that points to STT_SECTION. It would also be consistent with how we process relocations for string tail merging and ICF among other places, e.g. here. The downside is that it adds another special case for STT_SECTION but I guess that's fine.

Thanks for the explanation. I haven't read through the lld branch-to-branch optimization patch. However, I agree that adding a special case for STT_SECTION to the linker might be the right solution. Changing the assembler regarding PLT32 looks fishy.

I find the GNU Assembler change strange. I believe it should only apply to i386 (if we ever decide to dance with PLT32/PC32)

(See sourceware.org/bugzilla/show_bug.cgi?id=26263 for gas behavior. I do not follow the argument "Since PLT32 relocation must be against symbols". I don't know whether it fixed an issue in GNU ld's i386 port for the 32-bit case.)

@pcc
Copy link
Contributor Author

pcc commented May 9, 2025

Abandoning this and will address in the linker change (#138366) instead.

@pcc pcc closed this May 9, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants