[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