Remove MIPS-specific code from computeAddend.

Previously, computeAddend had many parameters but most of them were
used only for MIPS. The MIPS ABI is too odd that I don't want to mix
it into the regular code path. Splitting the function into non-MIPS
and MIPS parts makes the regular code path easy to follow.

llvm-svn: 298817
This commit is contained in:
Rui Ueyama 2017-03-26 19:35:24 +00:00
parent bae9202b9a
commit a2f63f1471
1 changed files with 56 additions and 51 deletions

View File

@ -237,9 +237,8 @@ handleTlsRelocation(uint32_t Type, SymbolBody &Body, InputSectionBase &C,
return 0;
}
template <class RelTy>
static uint32_t getMipsPairType(const RelTy *Rel, const SymbolBody &Sym) {
switch (Rel->getType(Config->IsMips64EL)) {
static uint32_t getMipsPairType(uint32_t Type, const SymbolBody &Sym) {
switch (Type) {
case R_MIPS_HI16:
return R_MIPS_LO16;
case R_MIPS_GOT16:
@ -253,37 +252,6 @@ static uint32_t getMipsPairType(const RelTy *Rel, const SymbolBody &Sym) {
}
}
template <class RelTy>
static int32_t findMipsPairedAddend(const uint8_t *Buf, const uint8_t *BufLoc,
SymbolBody &Sym, const RelTy *Rel,
const RelTy *End) {
uint32_t SymIndex = Rel->getSymbol(Config->IsMips64EL);
uint32_t Type = getMipsPairType(Rel, Sym);
// Some MIPS relocations use addend calculated from addend of the relocation
// itself and addend of paired relocation. ABI requires to compute such
// combined addend in case of REL relocation record format only.
// See p. 4-17 at ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
if (RelTy::IsRela || Type == R_MIPS_NONE)
return 0;
for (const RelTy *RI = Rel; RI != End; ++RI) {
if (RI->getType(Config->IsMips64EL) != Type)
continue;
if (RI->getSymbol(Config->IsMips64EL) != SymIndex)
continue;
endianness E = Config->Endianness;
int32_t Hi = (read32(BufLoc, E) & 0xffff) << 16;
int32_t Lo = SignExtend32<16>(read32(Buf + RI->r_offset, E));
return Hi + Lo;
}
warn("can't find matching " + toString(Type) + " relocation for " +
toString(Rel->getType(Config->IsMips64EL)));
return 0;
}
// True if non-preemptable symbol always has the same value regardless of where
// the DSO is loaded.
static bool isAbsolute(const SymbolBody &Body) {
@ -581,26 +549,62 @@ static RelExpr adjustExpr(SymbolBody &Body, RelExpr Expr, uint32_t Type,
return Expr;
}
// Returns an addend of a given relocation. If it is RELA, an addend
// is in a relocation itself. If it is REL, we need to read it from an
// input section.
template <class ELFT, class RelTy>
static int64_t computeAddend(const elf::ObjectFile<ELFT> &File,
const uint8_t *SectionData, const RelTy *End,
const RelTy &Rel, RelExpr Expr, SymbolBody &Body) {
static int64_t computeAddend(const RelTy &Rel, const uint8_t *Buf) {
int64_t A = getAddend<ELFT>(Rel);
uint32_t Type = Rel.getType(Config->IsMips64EL);
int64_t Addend = getAddend<ELFT>(Rel);
const uint8_t *BufLoc = SectionData + Rel.r_offset;
if (!RelTy::IsRela)
Addend += Target->getImplicitAddend(BufLoc, Type);
A += Target->getImplicitAddend(Buf + Rel.r_offset, Type);
if (Config->EMachine == EM_PPC64 && Config->Pic && Type == R_PPC64_TOC)
A += getPPC64TocBase();
return A;
}
if (Config->EMachine == EM_MIPS) {
Addend += findMipsPairedAddend(SectionData, BufLoc, Body, &Rel, End);
if (Expr == R_MIPS_GOTREL && Body.isLocal())
Addend += File.MipsGp0;
// MIPS has an odd notion of "paired" relocations to calculate addends.
// For example, if a relocation is of R_MIPS_HI16, there must be a
// R_MIPS_LO16 relocation after that, and an addend is calculated using
// the two relocations.
template <class ELFT, class RelTy>
static int64_t computeMipsAddend(const RelTy &Rel, InputSectionBase &Sec,
RelExpr Expr, SymbolBody &Body,
const RelTy *End) {
if (Expr == R_MIPS_GOTREL && Body.isLocal())
return Sec.getFile<ELFT>()->MipsGp0;
// The ABI says that the paired relocation is used only for REL.
// See p. 4-17 at ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
if (RelTy::IsRela)
return 0;
uint32_t Type = Rel.getType(Config->IsMips64EL);
uint32_t PairTy = getMipsPairType(Type, Body);
if (PairTy == R_MIPS_NONE)
return 0;
const uint8_t *Buf = Sec.Data.data();
uint32_t SymIndex = Rel.getSymbol(Config->IsMips64EL);
// To make things worse, paired relocations might not be contiguous in
// the relocation table, so we need to do linear search. *sigh*
for (const RelTy *RI = &Rel; RI != End; ++RI) {
if (RI->getType(Config->IsMips64EL) != PairTy)
continue;
if (RI->getSymbol(Config->IsMips64EL) != SymIndex)
continue;
endianness E = Config->Endianness;
int32_t Hi = (read32(Buf + Rel.r_offset, E) & 0xffff) << 16;
int32_t Lo = SignExtend32<16>(read32(Buf + RI->r_offset, E));
return Hi + Lo;
}
if (Config->Pic && Config->EMachine == EM_PPC64 && Type == R_PPC64_TOC)
Addend += getPPC64TocBase();
return Addend;
warn("can't find matching " + toString(PairTy) + " relocation for " +
toString(Type));
return 0;
}
template <class ELFT>
@ -719,7 +723,7 @@ template <class ELFT, class RelTy>
static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) {
OffsetGetter GetOffset(Sec);
for (auto I = Rels.begin(), E = Rels.end(); I != E; ++I) {
for (auto I = Rels.begin(), End = Rels.end(); I != End; ++I) {
const RelTy &Rel = *I;
SymbolBody &Body = Sec.getFile<ELFT>()->getRelocTargetSym(Rel);
uint32_t Type = Rel.getType(Config->IsMips64EL);
@ -727,7 +731,7 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) {
if (Config->MipsN32Abi) {
uint32_t Processed;
std::tie(Type, Processed) =
mergeMipsN32RelTypes(Type, Rel.r_offset, I + 1, E);
mergeMipsN32RelTypes(Type, Rel.r_offset, I + 1, End);
I += Processed;
}
@ -761,8 +765,9 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) {
R_GOTREL_FROM_END, R_PPC_TOC>(Expr))
In<ELFT>::Got->HasGotOffRel = true;
int64_t Addend = computeAddend(*Sec.getFile<ELFT>(), Sec.Data.data(), E,
Rel, Expr, Body);
int64_t Addend = computeAddend<ELFT>(Rel, Sec.Data.data());
if (Config->EMachine == EM_MIPS)
Addend += computeMipsAddend<ELFT>(Rel, Sec, Expr, Body, End);
if (unsigned Processed =
handleTlsRelocation<ELFT>(Type, Body, Sec, Offset, Addend, Expr)) {