[PATCH] D29714: [ELF] - Do sign extend for addends of R_386_8, R_386_16 relocations

Rafael EspĂ­ndola via llvm-commits llvm-commits at lists.llvm.org
Mon Feb 13 15:11:39 PST 2017


Looking more into the problem I think George is right that the addend
has to be sign extended, but I think it is a far more general issue.

My confusion was from what it means for a relocation to be unsigned. I
think the answer is just that the value at runtime will be zero
extended. It should say nothing about the addend. In fact, I think the
correct solution is to say that addends on ELF are always signed. That
is true even for Elf_Rela.

We were not hitting problems with Elf_Rela because we were very
careful to always use uintX_t, and that produces the same result. But
is easier and more explicit IMHO to use int64_t for both explicit and
implicit addends.

So how about the attached patch?

Sorry again for the delay and confusion.

Cheers,
Rafael
-------------- next part --------------
diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp
index 9b21a32..5d25cbb 100644
--- a/ELF/InputSection.cpp
+++ b/ELF/InputSection.cpp
@@ -246,7 +246,7 @@ void InputSection<ELFT>::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) {
                        cast<DefinedRegular<ELFT>>(Body).Section->OutSec->Addr;
       } else if (Config->Relocatable) {
         const uint8_t *BufLoc = RelocatedSection->Data.begin() + Rel.r_offset;
-        uint64_t Implicit = Target->getImplicitAddend(BufLoc, Type);
+        int64_t Implicit = Target->getImplicitAddend(BufLoc, Type);
         RelocatedSection->Relocations.push_back(
             {R_ABS, Type, Rel.r_offset, Implicit, &Body});
       }
@@ -297,7 +297,7 @@ static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t Type, uint64_t A,
 
 template <class ELFT>
 static typename ELFT::uint
-getRelocTargetVA(uint32_t Type, typename ELFT::uint A, typename ELFT::uint P,
+getRelocTargetVA(uint32_t Type, int64_t A, typename ELFT::uint P,
                  const SymbolBody &Body, RelExpr Expr) {
   switch (Expr) {
   case R_HINT:
@@ -447,7 +447,7 @@ void InputSection<ELFT>::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) {
     uint32_t Type = Rel.getType(Config->Mips64EL);
     uintX_t Offset = this->getOffset(Rel.r_offset);
     uint8_t *BufLoc = Buf + Offset;
-    uintX_t Addend = getAddend<ELFT>(Rel);
+    int64_t Addend = getAddend<ELFT>(Rel);
     if (!RelTy::IsRela)
       Addend += Target->getImplicitAddend(BufLoc, Type);
 
@@ -485,12 +485,11 @@ void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd) {
     uintX_t Offset = getOffset(Rel.Offset);
     uint8_t *BufLoc = Buf + Offset;
     uint32_t Type = Rel.Type;
-    uintX_t A = Rel.Addend;
 
     uintX_t AddrLoc = OutSec->Addr + Offset;
     RelExpr Expr = Rel.Expr;
     uint64_t TargetVA = SignExtend64<Bits>(
-        getRelocTargetVA<ELFT>(Type, A, AddrLoc, *Rel.Sym, Expr));
+        getRelocTargetVA<ELFT>(Type, Rel.Addend, AddrLoc, *Rel.Sym, Expr));
 
     switch (Expr) {
     case R_RELAX_GOT_PC:
diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp
index 3e2ef42..8841546 100644
--- a/ELF/Relocations.cpp
+++ b/ELF/Relocations.cpp
@@ -91,9 +91,11 @@ static bool isPreemptible(const SymbolBody &Body, uint32_t Type) {
 // handling in to the separate function we can simplify the code and do not
 // pollute `handleTlsRelocation` by ARM and MIPS `ifs` statements.
 template <class ELFT, class GOT>
-static unsigned handleNoRelaxTlsRelocation(
-    GOT *Got, uint32_t Type, SymbolBody &Body, InputSectionBase<ELFT> &C,
-    typename ELFT::uint Offset, typename ELFT::uint Addend, RelExpr Expr) {
+static unsigned handleNoRelaxTlsRelocation(GOT *Got, uint32_t Type,
+                                           SymbolBody &Body,
+                                           InputSectionBase<ELFT> &C,
+                                           typename ELFT::uint Offset,
+                                           int64_t Addend, RelExpr Expr) {
   typedef typename ELFT::uint uintX_t;
   auto addModuleReloc = [](SymbolBody &Body, GOT *Got, uintX_t Off, bool LD) {
     // The Dynamic TLS Module Index Relocation can be statically resolved to 1
@@ -133,10 +135,9 @@ static unsigned handleNoRelaxTlsRelocation(
 
 // Returns the number of relocations processed.
 template <class ELFT>
-static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body,
-                                    InputSectionBase<ELFT> &C,
-                                    typename ELFT::uint Offset,
-                                    typename ELFT::uint Addend, RelExpr Expr) {
+static unsigned
+handleTlsRelocation(uint32_t Type, SymbolBody &Body, InputSectionBase<ELFT> &C,
+                    typename ELFT::uint Offset, int64_t Addend, RelExpr Expr) {
   if (!(C.Flags & SHF_ALLOC))
     return 0;
 
@@ -530,14 +531,11 @@ static RelExpr adjustExpr(const elf::ObjectFile<ELFT> &File, SymbolBody &Body,
 }
 
 template <class ELFT, class RelTy>
-static typename ELFT::uint computeAddend(const elf::ObjectFile<ELFT> &File,
-                                         const uint8_t *SectionData,
-                                         const RelTy *End, const RelTy &RI,
-                                         RelExpr Expr, SymbolBody &Body) {
-  typedef typename ELFT::uint uintX_t;
-
+static int64_t computeAddend(const elf::ObjectFile<ELFT> &File,
+                             const uint8_t *SectionData, const RelTy *End,
+                             const RelTy &RI, RelExpr Expr, SymbolBody &Body) {
   uint32_t Type = RI.getType(Config->Mips64EL);
-  uintX_t Addend = getAddend<ELFT>(RI);
+  int64_t Addend = getAddend<ELFT>(RI);
   const uint8_t *BufLoc = SectionData + RI.r_offset;
   if (!RelTy::IsRela)
     Addend += Target->getImplicitAddend(BufLoc, Type);
@@ -675,7 +673,7 @@ static void scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
         Expr == R_GOTREL || Expr == R_GOTREL_FROM_END || Expr == R_PPC_TOC)
       In<ELFT>::Got->HasGotOffRel = true;
 
-    uintX_t Addend = computeAddend(*File, Buf, E, RI, Expr, Body);
+    int64_t Addend = computeAddend(*File, Buf, E, RI, Expr, Body);
 
     if (unsigned Processed =
             handleTlsRelocation<ELFT>(Type, Body, C, Offset, Addend, Expr)) {
diff --git a/ELF/Relocations.h b/ELF/Relocations.h
index 2671b1e..6f77951 100644
--- a/ELF/Relocations.h
+++ b/ELF/Relocations.h
@@ -105,7 +105,7 @@ struct Relocation {
   RelExpr Expr;
   uint32_t Type;
   uint64_t Offset;
-  uint64_t Addend;
+  int64_t Addend;
   SymbolBody *Sym;
 };
 
@@ -114,14 +114,15 @@ template <class ELFT> void scanRelocations(InputSectionBase<ELFT> &);
 template <class ELFT>
 void createThunks(ArrayRef<OutputSectionBase *> OutputSections);
 
+// Return a int64_t to make sure we get the sign extension out of the way as
+// early as possible.
 template <class ELFT>
-static inline typename ELFT::uint getAddend(const typename ELFT::Rel &Rel) {
+static inline int64_t getAddend(const typename ELFT::Rel &Rel) {
   return 0;
 }
-
 template <class ELFT>
-static inline typename ELFT::uint getAddend(const typename ELFT::Rela &Rel) {
-  return Rel.r_addend;
+static inline int64_t getAddend(const typename ELFT::Rela &Rel) {
+  return llvm::SignExtend64 < ELFT::Is64Bits ? 64 : 32 > (Rel.r_addend);
 }
 }
 }
diff --git a/ELF/Symbols.cpp b/ELF/Symbols.cpp
index cefc624..ed32270 100644
--- a/ELF/Symbols.cpp
+++ b/ELF/Symbols.cpp
@@ -29,8 +29,7 @@ using namespace lld;
 using namespace lld::elf;
 
 template <class ELFT>
-static typename ELFT::uint getSymVA(const SymbolBody &Body,
-                                    typename ELFT::uint &Addend) {
+static typename ELFT::uint getSymVA(const SymbolBody &Body, int64_t &Addend) {
   typedef typename ELFT::uint uintX_t;
 
   switch (Body.kind()) {
@@ -135,7 +134,7 @@ bool SymbolBody::isPreemptible() const {
 }
 
 template <class ELFT>
-typename ELFT::uint SymbolBody::getVA(typename ELFT::uint Addend) const {
+typename ELFT::uint SymbolBody::getVA(int64_t Addend) const {
   typename ELFT::uint OutVA = getSymVA<ELFT>(*this, Addend);
   return OutVA + Addend;
 }
@@ -322,10 +321,10 @@ std::string lld::toString(const SymbolBody &B) {
   return B.getName();
 }
 
-template uint32_t SymbolBody::template getVA<ELF32LE>(uint32_t) const;
-template uint32_t SymbolBody::template getVA<ELF32BE>(uint32_t) const;
-template uint64_t SymbolBody::template getVA<ELF64LE>(uint64_t) const;
-template uint64_t SymbolBody::template getVA<ELF64BE>(uint64_t) const;
+template uint32_t SymbolBody::template getVA<ELF32LE>(int64_t) const;
+template uint32_t SymbolBody::template getVA<ELF32BE>(int64_t) const;
+template uint64_t SymbolBody::template getVA<ELF64LE>(int64_t) const;
+template uint64_t SymbolBody::template getVA<ELF64BE>(int64_t) const;
 
 template uint32_t SymbolBody::template getGotVA<ELF32LE>() const;
 template uint32_t SymbolBody::template getGotVA<ELF32BE>() const;
diff --git a/ELF/Symbols.h b/ELF/Symbols.h
index ed079ef..e8ae9b7 100644
--- a/ELF/Symbols.h
+++ b/ELF/Symbols.h
@@ -77,8 +77,7 @@ public:
   bool isInGot() const { return GotIndex != -1U; }
   bool isInPlt() const { return PltIndex != -1U; }
 
-  template <class ELFT>
-  typename ELFT::uint getVA(typename ELFT::uint Addend = 0) const;
+  template <class ELFT> typename ELFT::uint getVA(int64_t Addend = 0) const;
 
   template <class ELFT> typename ELFT::uint getGotOffset() const;
   template <class ELFT> typename ELFT::uint getGotVA() const;
diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp
index 44bd93f..bcab053 100644
--- a/ELF/SyntheticSections.cpp
+++ b/ELF/SyntheticSections.cpp
@@ -461,7 +461,7 @@ MipsGotSection<ELFT>::MipsGotSection()
                              SHT_PROGBITS, 16, ".got") {}
 
 template <class ELFT>
-void MipsGotSection<ELFT>::addEntry(SymbolBody &Sym, uintX_t Addend,
+void MipsGotSection<ELFT>::addEntry(SymbolBody &Sym, int64_t Addend,
                                     RelExpr Expr) {
   // For "true" local symbols which can be referenced from the same module
   // only compiler creates two instructions for address loading:
@@ -562,7 +562,7 @@ static uint64_t getMipsPageCount(uint64_t Size) {
 template <class ELFT>
 typename MipsGotSection<ELFT>::uintX_t
 MipsGotSection<ELFT>::getPageEntryOffset(const SymbolBody &B,
-                                         uintX_t Addend) const {
+                                         int64_t Addend) const {
   const OutputSectionBase *OutSec =
       cast<DefinedRegular<ELFT>>(&B)->Section->OutSec;
   uintX_t SecAddr = getMipsPageAddr(OutSec->Addr);
@@ -575,7 +575,7 @@ MipsGotSection<ELFT>::getPageEntryOffset(const SymbolBody &B,
 template <class ELFT>
 typename MipsGotSection<ELFT>::uintX_t
 MipsGotSection<ELFT>::getBodyEntryOffset(const SymbolBody &B,
-                                         uintX_t Addend) const {
+                                         int64_t Addend) const {
   // Calculate offset of the GOT entries block: TLS, global, local.
   uintX_t Index = HeaderEntriesNum + PageEntriesNum;
   if (B.isTls())
@@ -977,8 +977,7 @@ typename ELFT::uint DynamicReloc<ELFT>::getOffset() const {
   return InputSec->OutSec->Addr + InputSec->getOffset(OffsetInSec);
 }
 
-template <class ELFT>
-typename ELFT::uint DynamicReloc<ELFT>::getAddend() const {
+template <class ELFT> int64_t DynamicReloc<ELFT>::getAddend() const {
   if (UseSymVA)
     return Sym->getVA<ELFT>(Addend);
   return Addend;
diff --git a/ELF/SyntheticSections.h b/ELF/SyntheticSections.h
index 5765086..dfa9cfb 100644
--- a/ELF/SyntheticSections.h
+++ b/ELF/SyntheticSections.h
@@ -129,11 +129,11 @@ public:
   size_t getSize() const override { return Size; }
   void finalize() override;
   bool empty() const override;
-  void addEntry(SymbolBody &Sym, uintX_t Addend, RelExpr Expr);
+  void addEntry(SymbolBody &Sym, int64_t Addend, RelExpr Expr);
   bool addDynTlsEntry(SymbolBody &Sym);
   bool addTlsIndex();
-  uintX_t getPageEntryOffset(const SymbolBody &B, uintX_t Addend) const;
-  uintX_t getBodyEntryOffset(const SymbolBody &B, uintX_t Addend) const;
+  uintX_t getPageEntryOffset(const SymbolBody &B, int64_t Addend) const;
+  uintX_t getBodyEntryOffset(const SymbolBody &B, int64_t Addend) const;
   uintX_t getGlobalDynOffset(const SymbolBody &B) const;
 
   // Returns the symbol which corresponds to the first entry of the global part
@@ -279,12 +279,12 @@ template <class ELFT> class DynamicReloc {
 public:
   DynamicReloc(uint32_t Type, const InputSectionBase<ELFT> *InputSec,
                uintX_t OffsetInSec, bool UseSymVA, SymbolBody *Sym,
-               uintX_t Addend)
+               int64_t Addend)
       : Type(Type), Sym(Sym), InputSec(InputSec), OffsetInSec(OffsetInSec),
         UseSymVA(UseSymVA), Addend(Addend) {}
 
   uintX_t getOffset() const;
-  uintX_t getAddend() const;
+  int64_t getAddend() const;
   uint32_t getSymIndex() const;
   const InputSectionBase<ELFT> *getInputSec() const { return InputSec; }
 
@@ -295,7 +295,7 @@ private:
   const InputSectionBase<ELFT> *InputSec = nullptr;
   uintX_t OffsetInSec;
   bool UseSymVA;
-  uintX_t Addend;
+  int64_t Addend;
 };
 
 template <class ELFT>
diff --git a/ELF/Target.cpp b/ELF/Target.cpp
index 023c948..37ddac1 100644
--- a/ELF/Target.cpp
+++ b/ELF/Target.cpp
@@ -491,11 +491,9 @@ int64_t X86TargetInfo::getImplicitAddend(const uint8_t *Buf,
   default:
     return 0;
   case R_386_8:
-    return *Buf;
   case R_386_PC8:
     return SignExtend64<8>(*Buf);
   case R_386_16:
-    return read16le(Buf);
   case R_386_PC16:
     return SignExtend64<16>(read16le(Buf));
   case R_386_32:
@@ -506,7 +504,7 @@ int64_t X86TargetInfo::getImplicitAddend(const uint8_t *Buf,
   case R_386_PC32:
   case R_386_PLT32:
   case R_386_TLS_LE:
-    return read32le(Buf);
+    return SignExtend64<32>(read32le(Buf));
   }
 }
 
@@ -2264,7 +2262,7 @@ int64_t MipsTargetInfo<ELFT>::getImplicitAddend(const uint8_t *Buf,
   case R_MIPS_GPREL32:
   case R_MIPS_TLS_DTPREL32:
   case R_MIPS_TLS_TPREL32:
-    return read32<E>(Buf);
+    return SignExtend64<32>(read32<E>(Buf));
   case R_MIPS_26:
     // FIXME (simon): If the relocation target symbol is not a PLT entry
     // we should use another expression for calculation:
diff --git a/test/ELF/i386-reloc8-reloc16-addend.s b/test/ELF/i386-reloc8-reloc16-addend.s
new file mode 100644
index 0000000..16b953e
--- /dev/null
+++ b/test/ELF/i386-reloc8-reloc16-addend.s
@@ -0,0 +1,17 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=i386-pc-linux-gnu %s -o %t1.o
+
+# RUN: ld.lld -Ttext=0x0 %t1.o -o %t.out
+# RUN: llvm-objdump -s -t %t.out | FileCheck %s
+# CHECK:      Contents of section .text:
+# CHECK-NEXT:  0000 020100
+## 0x3 + addend(-1) = 0x02
+## 0x3 + addend(-2) = 0x0100
+# CHECK: SYMBOL TABLE:
+# CHECK: 00000003 .und
+
+.byte  und-1
+.short und-2
+
+.section .und, "ax"
+und:


More information about the llvm-commits mailing list