forked from OSchip/llvm-project
				
			ELF: Allow thunks to change size. NFCI.
Differential Revision: https://reviews.llvm.org/D44962 llvm-svn: 328841
This commit is contained in:
		
							parent
							
								
									4778bb88ef
								
							
						
					
					
						commit
						c5391ce51e
					
				| 
						 | 
				
			
			@ -1263,7 +1263,7 @@ std::pair<Thunk *, bool> ThunkCreator::getThunk(Symbol &Sym, RelType Type,
 | 
			
		|||
  // Check existing Thunks for Sym to see if they can be reused
 | 
			
		||||
  for (Thunk *ET : *ThunkVec)
 | 
			
		||||
    if (ET->isCompatibleWith(Type) &&
 | 
			
		||||
        Target->inBranchRange(Type, Src, ET->ThunkSym->getVA()))
 | 
			
		||||
        Target->inBranchRange(Type, Src, ET->getThunkTargetSym()->getVA()))
 | 
			
		||||
      return std::make_pair(ET, false);
 | 
			
		||||
  // No existing compatible Thunk in range, create a new one
 | 
			
		||||
  Thunk *T = addThunk(Type, Sym);
 | 
			
		||||
| 
						 | 
				
			
			@ -1358,7 +1358,6 @@ bool ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) {
 | 
			
		|||
            bool IsNew;
 | 
			
		||||
            std::tie(T, IsNew) = getThunk(*Rel.Sym, Rel.Type, Src);
 | 
			
		||||
            if (IsNew) {
 | 
			
		||||
              AddressesChanged = true;
 | 
			
		||||
              // Find or create a ThunkSection for the new Thunk
 | 
			
		||||
              ThunkSection *TS;
 | 
			
		||||
              if (auto *TIS = T->getTargetInputSection())
 | 
			
		||||
| 
						 | 
				
			
			@ -1366,13 +1365,18 @@ bool ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) {
 | 
			
		|||
              else
 | 
			
		||||
                TS = getISDThunkSec(OS, IS, ISD, Rel.Type, Src);
 | 
			
		||||
              TS->addThunk(T);
 | 
			
		||||
              Thunks[T->ThunkSym] = T;
 | 
			
		||||
              Thunks[T->getThunkTargetSym()] = T;
 | 
			
		||||
            }
 | 
			
		||||
            // Redirect relocation to Thunk, we never go via the PLT to a Thunk
 | 
			
		||||
            Rel.Sym = T->ThunkSym;
 | 
			
		||||
            Rel.Sym = T->getThunkTargetSym();
 | 
			
		||||
            Rel.Expr = fromPlt(Rel.Expr);
 | 
			
		||||
          }
 | 
			
		||||
        for (auto &P : ISD->ThunkSections)
 | 
			
		||||
          AddressesChanged |= P.first->assignOffsets();
 | 
			
		||||
      });
 | 
			
		||||
  for (auto &P : ThunkedSections)
 | 
			
		||||
    AddressesChanged |= P.second->assignOffsets();
 | 
			
		||||
 | 
			
		||||
  // Merge all created synthetic ThunkSections back into OutputSection
 | 
			
		||||
  mergeThunks(OutputSections);
 | 
			
		||||
  ++Pass;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -264,7 +264,7 @@ InputSection *elf::createInterpSection() {
 | 
			
		|||
  return Sec;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Symbol *elf::addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value,
 | 
			
		||||
Defined *elf::addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value,
 | 
			
		||||
                                uint64_t Size, InputSectionBase &Section) {
 | 
			
		||||
  auto *S = make<Defined>(Section.File, Name, STB_LOCAL, STV_DEFAULT, Type,
 | 
			
		||||
                          Value, Size, &Section);
 | 
			
		||||
| 
						 | 
				
			
			@ -2621,11 +2621,8 @@ ThunkSection::ThunkSection(OutputSection *OS, uint64_t Off)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void ThunkSection::addThunk(Thunk *T) {
 | 
			
		||||
  uint64_t Off = alignTo(Size, T->Alignment);
 | 
			
		||||
  T->Offset = Off;
 | 
			
		||||
  Thunks.push_back(T);
 | 
			
		||||
  T->addSymbols(*this);
 | 
			
		||||
  Size = Off + T->size();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ThunkSection::writeTo(uint8_t *Buf) {
 | 
			
		||||
| 
						 | 
				
			
			@ -2640,6 +2637,20 @@ InputSection *ThunkSection::getTargetInputSection() const {
 | 
			
		|||
  return T->getTargetInputSection();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ThunkSection::assignOffsets() {
 | 
			
		||||
  uint64_t Off = 0;
 | 
			
		||||
  for (Thunk *T : Thunks) {
 | 
			
		||||
    Off = alignTo(Off, T->Alignment);
 | 
			
		||||
    T->setOffset(Off);
 | 
			
		||||
    uint32_t Size = T->size();
 | 
			
		||||
    T->getThunkTargetSym()->Size = Size;
 | 
			
		||||
    Off += Size;
 | 
			
		||||
  }
 | 
			
		||||
  bool Changed = Off != Size;
 | 
			
		||||
  Size = Off;
 | 
			
		||||
  return Changed;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
InputSection *InX::ARMAttributes;
 | 
			
		||||
BssSection *InX::Bss;
 | 
			
		||||
BssSection *InX::BssRelRo;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,6 +30,7 @@
 | 
			
		|||
 | 
			
		||||
namespace lld {
 | 
			
		||||
namespace elf {
 | 
			
		||||
class Defined;
 | 
			
		||||
class SharedSymbol;
 | 
			
		||||
 | 
			
		||||
class SyntheticSection : public InputSection {
 | 
			
		||||
| 
						 | 
				
			
			@ -823,6 +824,7 @@ public:
 | 
			
		|||
  size_t getSize() const override { return Size; }
 | 
			
		||||
  void writeTo(uint8_t *Buf) override;
 | 
			
		||||
  InputSection *getTargetInputSection() const;
 | 
			
		||||
  bool assignOffsets();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
  std::vector<Thunk *> Thunks;
 | 
			
		||||
| 
						 | 
				
			
			@ -834,7 +836,7 @@ MergeInputSection *createCommentSection();
 | 
			
		|||
void decompressSections();
 | 
			
		||||
void mergeSections();
 | 
			
		||||
 | 
			
		||||
Symbol *addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value,
 | 
			
		||||
Defined *addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value,
 | 
			
		||||
                           uint64_t Size, InputSectionBase &Section);
 | 
			
		||||
 | 
			
		||||
// Linker generated sections which can be used as inputs.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -141,6 +141,19 @@ public:
 | 
			
		|||
 | 
			
		||||
} // end anonymous namespace
 | 
			
		||||
 | 
			
		||||
Defined *Thunk::addSymbol(StringRef Name, uint8_t Type, uint64_t Value,
 | 
			
		||||
                          InputSectionBase &Section) {
 | 
			
		||||
  Defined *D = addSyntheticLocal(Name, Type, Value, /*Size=*/0, Section);
 | 
			
		||||
  Syms.push_back(D);
 | 
			
		||||
  return D;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Thunk::setOffset(uint64_t NewOffset) {
 | 
			
		||||
  for (Defined *D : Syms)
 | 
			
		||||
    D->Value = D->Value - Offset + NewOffset;
 | 
			
		||||
  Offset = NewOffset;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AArch64 long range Thunks
 | 
			
		||||
 | 
			
		||||
static uint64_t getAArch64ThunkDestVA(const Symbol &S) {
 | 
			
		||||
| 
						 | 
				
			
			@ -161,11 +174,10 @@ void AArch64ABSLongThunk::writeTo(uint8_t *Buf) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void AArch64ABSLongThunk::addSymbols(ThunkSection &IS) {
 | 
			
		||||
  ThunkSym = addSyntheticLocal(
 | 
			
		||||
      Saver.save("__AArch64AbsLongThunk_" + Destination.getName()), STT_FUNC,
 | 
			
		||||
      Offset, size(), IS);
 | 
			
		||||
  addSyntheticLocal("$x", STT_NOTYPE, Offset, 0, IS);
 | 
			
		||||
  addSyntheticLocal("$d", STT_NOTYPE, Offset + 8, 0, IS);
 | 
			
		||||
  addSymbol(Saver.save("__AArch64AbsLongThunk_" + Destination.getName()),
 | 
			
		||||
            STT_FUNC, 0, IS);
 | 
			
		||||
  addSymbol("$x", STT_NOTYPE, 0, IS);
 | 
			
		||||
  addSymbol("$d", STT_NOTYPE, 8, IS);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// This Thunk has a maximum range of 4Gb, this is sufficient for all programs
 | 
			
		||||
| 
						 | 
				
			
			@ -180,19 +192,17 @@ void AArch64ADRPThunk::writeTo(uint8_t *Buf) {
 | 
			
		|||
      0x00, 0x02, 0x1f, 0xd6, // br   x16
 | 
			
		||||
  };
 | 
			
		||||
  uint64_t S = getAArch64ThunkDestVA(Destination);
 | 
			
		||||
  uint64_t P = ThunkSym->getVA();
 | 
			
		||||
  uint64_t P = getThunkTargetSym()->getVA();
 | 
			
		||||
  memcpy(Buf, Data, sizeof(Data));
 | 
			
		||||
  Target->relocateOne(Buf, R_AARCH64_ADR_PREL_PG_HI21,
 | 
			
		||||
                      getAArch64Page(S) - getAArch64Page(P));
 | 
			
		||||
  Target->relocateOne(Buf + 4, R_AARCH64_ADD_ABS_LO12_NC, S);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AArch64ADRPThunk::addSymbols(ThunkSection &IS)
 | 
			
		||||
{
 | 
			
		||||
  ThunkSym = addSyntheticLocal(
 | 
			
		||||
      Saver.save("__AArch64ADRPThunk_" + Destination.getName()), STT_FUNC,
 | 
			
		||||
      Offset, size(), IS);
 | 
			
		||||
  addSyntheticLocal("$x", STT_NOTYPE, Offset, 0, IS);
 | 
			
		||||
void AArch64ADRPThunk::addSymbols(ThunkSection &IS) {
 | 
			
		||||
  addSymbol(Saver.save("__AArch64ADRPThunk_" + Destination.getName()), STT_FUNC,
 | 
			
		||||
            0, IS);
 | 
			
		||||
  addSymbol("$x", STT_NOTYPE, 0, IS);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ARM Target Thunks
 | 
			
		||||
| 
						 | 
				
			
			@ -214,10 +224,9 @@ void ARMV7ABSLongThunk::writeTo(uint8_t *Buf) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void ARMV7ABSLongThunk::addSymbols(ThunkSection &IS) {
 | 
			
		||||
  ThunkSym = addSyntheticLocal(
 | 
			
		||||
      Saver.save("__ARMv7ABSLongThunk_" + Destination.getName()), STT_FUNC,
 | 
			
		||||
      Offset, size(), IS);
 | 
			
		||||
  addSyntheticLocal("$a", STT_NOTYPE, Offset, 0, IS);
 | 
			
		||||
  addSymbol(Saver.save("__ARMv7ABSLongThunk_" + Destination.getName()),
 | 
			
		||||
            STT_FUNC, 0, IS);
 | 
			
		||||
  addSymbol("$a", STT_NOTYPE, 0, IS);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ARMV7ABSLongThunk::isCompatibleWith(RelType Type) const {
 | 
			
		||||
| 
						 | 
				
			
			@ -238,10 +247,9 @@ void ThumbV7ABSLongThunk::writeTo(uint8_t *Buf) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void ThumbV7ABSLongThunk::addSymbols(ThunkSection &IS) {
 | 
			
		||||
  ThunkSym = addSyntheticLocal(
 | 
			
		||||
      Saver.save("__Thumbv7ABSLongThunk_" + Destination.getName()), STT_FUNC,
 | 
			
		||||
      Offset | 0x1, size(), IS);
 | 
			
		||||
  addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, IS);
 | 
			
		||||
  addSymbol(Saver.save("__Thumbv7ABSLongThunk_" + Destination.getName()),
 | 
			
		||||
            STT_FUNC, 1, IS);
 | 
			
		||||
  addSymbol("$t", STT_NOTYPE, 0, IS);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ThumbV7ABSLongThunk::isCompatibleWith(RelType Type) const {
 | 
			
		||||
| 
						 | 
				
			
			@ -257,7 +265,7 @@ void ARMV7PILongThunk::writeTo(uint8_t *Buf) {
 | 
			
		|||
      0x1c, 0xff, 0x2f, 0xe1, //     bx r12
 | 
			
		||||
  };
 | 
			
		||||
  uint64_t S = getARMThunkDestVA(Destination);
 | 
			
		||||
  uint64_t P = ThunkSym->getVA();
 | 
			
		||||
  uint64_t P = getThunkTargetSym()->getVA();
 | 
			
		||||
  uint64_t Offset = S - P - 16;
 | 
			
		||||
  memcpy(Buf, Data, sizeof(Data));
 | 
			
		||||
  Target->relocateOne(Buf, R_ARM_MOVW_PREL_NC, Offset);
 | 
			
		||||
| 
						 | 
				
			
			@ -265,10 +273,9 @@ void ARMV7PILongThunk::writeTo(uint8_t *Buf) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void ARMV7PILongThunk::addSymbols(ThunkSection &IS) {
 | 
			
		||||
  ThunkSym = addSyntheticLocal(
 | 
			
		||||
      Saver.save("__ARMV7PILongThunk_" + Destination.getName()), STT_FUNC,
 | 
			
		||||
      Offset, size(), IS);
 | 
			
		||||
  addSyntheticLocal("$a", STT_NOTYPE, Offset, 0, IS);
 | 
			
		||||
  addSymbol(Saver.save("__ARMV7PILongThunk_" + Destination.getName()), STT_FUNC,
 | 
			
		||||
            0, IS);
 | 
			
		||||
  addSymbol("$a", STT_NOTYPE, 0, IS);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ARMV7PILongThunk::isCompatibleWith(RelType Type) const {
 | 
			
		||||
| 
						 | 
				
			
			@ -284,7 +291,7 @@ void ThumbV7PILongThunk::writeTo(uint8_t *Buf) {
 | 
			
		|||
      0x60, 0x47,             //     bx   r12
 | 
			
		||||
  };
 | 
			
		||||
  uint64_t S = getARMThunkDestVA(Destination);
 | 
			
		||||
  uint64_t P = ThunkSym->getVA() & ~0x1;
 | 
			
		||||
  uint64_t P = getThunkTargetSym()->getVA() & ~0x1;
 | 
			
		||||
  uint64_t Offset = S - P - 12;
 | 
			
		||||
  memcpy(Buf, Data, sizeof(Data));
 | 
			
		||||
  Target->relocateOne(Buf, R_ARM_THM_MOVW_PREL_NC, Offset);
 | 
			
		||||
| 
						 | 
				
			
			@ -292,10 +299,9 @@ void ThumbV7PILongThunk::writeTo(uint8_t *Buf) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void ThumbV7PILongThunk::addSymbols(ThunkSection &IS) {
 | 
			
		||||
  ThunkSym = addSyntheticLocal(
 | 
			
		||||
      Saver.save("__ThumbV7PILongThunk_" + Destination.getName()), STT_FUNC,
 | 
			
		||||
      Offset | 0x1, size(), IS);
 | 
			
		||||
  addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, IS);
 | 
			
		||||
  addSymbol(Saver.save("__ThumbV7PILongThunk_" + Destination.getName()),
 | 
			
		||||
            STT_FUNC, 1, IS);
 | 
			
		||||
  addSymbol("$t", STT_NOTYPE, 0, IS);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ThumbV7PILongThunk::isCompatibleWith(RelType Type) const {
 | 
			
		||||
| 
						 | 
				
			
			@ -315,9 +321,8 @@ void MipsThunk::writeTo(uint8_t *Buf) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void MipsThunk::addSymbols(ThunkSection &IS) {
 | 
			
		||||
  ThunkSym =
 | 
			
		||||
      addSyntheticLocal(Saver.save("__LA25Thunk_" + Destination.getName()),
 | 
			
		||||
                        STT_FUNC, Offset, size(), IS);
 | 
			
		||||
  addSymbol(Saver.save("__LA25Thunk_" + Destination.getName()), STT_FUNC, 0,
 | 
			
		||||
            IS);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
InputSection *MipsThunk::getTargetInputSection() const {
 | 
			
		||||
| 
						 | 
				
			
			@ -339,10 +344,9 @@ void MicroMipsThunk::writeTo(uint8_t *Buf) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void MicroMipsThunk::addSymbols(ThunkSection &IS) {
 | 
			
		||||
  ThunkSym =
 | 
			
		||||
      addSyntheticLocal(Saver.save("__microLA25Thunk_" + Destination.getName()),
 | 
			
		||||
                        STT_FUNC, Offset, size(), IS);
 | 
			
		||||
  ThunkSym->StOther |= STO_MIPS_MICROMIPS;
 | 
			
		||||
  Defined *D = addSymbol(
 | 
			
		||||
      Saver.save("__microLA25Thunk_" + Destination.getName()), STT_FUNC, 0, IS);
 | 
			
		||||
  D->StOther |= STO_MIPS_MICROMIPS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
InputSection *MicroMipsThunk::getTargetInputSection() const {
 | 
			
		||||
| 
						 | 
				
			
			@ -354,7 +358,7 @@ InputSection *MicroMipsThunk::getTargetInputSection() const {
 | 
			
		|||
// to call PIC function from the non-PIC one.
 | 
			
		||||
void MicroMipsR6Thunk::writeTo(uint8_t *Buf) {
 | 
			
		||||
  uint64_t S = Destination.getVA() | 1;
 | 
			
		||||
  uint64_t P = ThunkSym->getVA();
 | 
			
		||||
  uint64_t P = getThunkTargetSym()->getVA();
 | 
			
		||||
  write16(Buf, 0x1320);       // lui   $25, %hi(func)
 | 
			
		||||
  write16(Buf + 4, 0x3339);   // addiu $25, $25, %lo(func)
 | 
			
		||||
  write16(Buf + 8, 0x9400);   // bc    func
 | 
			
		||||
| 
						 | 
				
			
			@ -364,10 +368,9 @@ void MicroMipsR6Thunk::writeTo(uint8_t *Buf) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void MicroMipsR6Thunk::addSymbols(ThunkSection &IS) {
 | 
			
		||||
  ThunkSym =
 | 
			
		||||
      addSyntheticLocal(Saver.save("__microLA25Thunk_" + Destination.getName()),
 | 
			
		||||
                        STT_FUNC, Offset, size(), IS);
 | 
			
		||||
  ThunkSym->StOther |= STO_MIPS_MICROMIPS;
 | 
			
		||||
  Defined *D = addSymbol(
 | 
			
		||||
      Saver.save("__microLA25Thunk_" + Destination.getName()), STT_FUNC, 0, IS);
 | 
			
		||||
  D->StOther |= STO_MIPS_MICROMIPS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
InputSection *MicroMipsR6Thunk::getTargetInputSection() const {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,6 +14,7 @@
 | 
			
		|||
 | 
			
		||||
namespace lld {
 | 
			
		||||
namespace elf {
 | 
			
		||||
class Defined;
 | 
			
		||||
class Symbol;
 | 
			
		||||
class ThunkSection;
 | 
			
		||||
// Class to describe an instance of a Thunk.
 | 
			
		||||
| 
						 | 
				
			
			@ -33,10 +34,15 @@ public:
 | 
			
		|||
  virtual uint32_t size() = 0;
 | 
			
		||||
  virtual void writeTo(uint8_t *Buf) = 0;
 | 
			
		||||
 | 
			
		||||
  // All Thunks must define at least one symbol ThunkSym so that we can
 | 
			
		||||
  // redirect relocations to it.
 | 
			
		||||
  // All Thunks must define at least one symbol, known as the thunk target
 | 
			
		||||
  // symbol, so that we can redirect relocations to it. The thunk may define
 | 
			
		||||
  // additional symbols, but these are never targets for relocations.
 | 
			
		||||
  virtual void addSymbols(ThunkSection &IS) = 0;
 | 
			
		||||
 | 
			
		||||
  void setOffset(uint64_t Offset);
 | 
			
		||||
  Defined *addSymbol(StringRef Name, uint8_t Type, uint64_t Value,
 | 
			
		||||
                     InputSectionBase &Section);
 | 
			
		||||
 | 
			
		||||
  // Some Thunks must be placed immediately before their Target as they elide
 | 
			
		||||
  // a branch and fall through to the first Symbol in the Target.
 | 
			
		||||
  virtual InputSection *getTargetInputSection() const { return nullptr; }
 | 
			
		||||
| 
						 | 
				
			
			@ -45,10 +51,12 @@ public:
 | 
			
		|||
  // compatible with it.
 | 
			
		||||
  virtual bool isCompatibleWith(RelType Type) const { return true; }
 | 
			
		||||
 | 
			
		||||
  Defined *getThunkTargetSym() const { return Syms[0]; }
 | 
			
		||||
 | 
			
		||||
  // The alignment requirement for this Thunk, defaults to the size of the
 | 
			
		||||
  // typical code section alignment.
 | 
			
		||||
  Symbol &Destination;
 | 
			
		||||
  Symbol *ThunkSym;
 | 
			
		||||
  llvm::SmallVector<Defined *, 3> Syms;
 | 
			
		||||
  uint64_t Offset = 0;
 | 
			
		||||
  uint32_t Alignment = 4;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue