Skip to content
Relocations.cpp 44.5 KiB
Newer Older
ThunkSection *ThunkCreator::getOSThunkSec(OutputSection *OS,
                                          std::vector<InputSection *> *ISR) {
    uint32_t Off = 0;
    for (auto *IS : OS->Sections) {
      Off = IS->OutSecOff + IS->getSize();
      if ((IS->Flags & SHF_EXECINSTR) == 0)
        break;
    }
    CurTS = addThunkSection(OS, ISR, Off);
ThunkSection *ThunkCreator::getISThunkSec(InputSection *IS, OutputSection *OS) {
  ThunkSection *TS = ThunkedSections.lookup(IS);
  if (TS)
    return TS;
  auto *TOS = IS->getParent();

  // Find InputSectionRange within TOS that IS is in
  OutputSectionCommand *C = Script->getCmd(TOS);
  std::vector<InputSection *> *Range = nullptr;
  for (BaseCommand *BC : C->Commands)
    if (auto *ISD = dyn_cast<InputSectionDescription> (BC)) {
      InputSection *first = ISD->Sections.front();
      InputSection *last = ISD->Sections.back();
      if (IS->OutSecOff >= first->OutSecOff &&
          IS->OutSecOff <= last->OutSecOff) {
        Range = &ISD->Sections;
        break;
      }
    }
  TS = addThunkSection(TOS, Range, IS->OutSecOff);
  ThunkedSections[IS] = TS;
  return TS;
}

ThunkSection *ThunkCreator::addThunkSection(OutputSection *OS,
                                            std::vector<InputSection *> *ISR,
                                            uint64_t Off) {
  auto *TS = make<ThunkSection>(OS, Off);
  ThunkSections[ISR].push_back(TS);
  return TS;
}


std::pair<Thunk *, bool> ThunkCreator::getThunk(SymbolBody &Body,
                                                uint32_t Type) {
  auto res = ThunkedSymbols.insert({&Body, nullptr});
  if (res.second)
    res.first->second = addThunk(Type, Body);
  return std::make_pair(res.first->second, res.second);
}

// Call Fn on every executable InputSection accessed via the linker script
// InputSectionDescription::Sections.
void ThunkCreator::forEachExecInputSection(
    ArrayRef<OutputSectionCommand *> OutputSections,
    std::function<void(OutputSection *, std::vector<InputSection *> *,
                       InputSection *)>
        Fn) {
  for (OutputSectionCommand *Cmd : OutputSections) {
    OutputSection *OS = Cmd->Sec;
    if (!(OS->Flags & SHF_ALLOC) || !(OS->Flags & SHF_EXECINSTR))
      continue;
    if (OutputSectionCommand *C = Script->getCmd(OS))
      for (BaseCommand *BC : C->Commands)
        if (auto *ISD = dyn_cast<InputSectionDescription>(BC)) {
          CurTS = nullptr;
          for (InputSection* IS : ISD->Sections)
            Fn(OS, &ISD->Sections, IS);
        }
// Process all relocations from the InputSections that have been assigned
// to OutputSections and redirect through Thunks if needed.
//
// createThunks must be called after scanRelocs has created the Relocations for
// each InputSection. It must be called before the static symbol table is
// finalized. If any Thunks are added to an OutputSection the output section
// offsets of the InputSections will change.
//
// FIXME: All Thunks are assumed to be in range of the relocation. Range
// extension Thunks are not yet supported.
bool ThunkCreator::createThunks(
    ArrayRef<OutputSectionCommand *> OutputSections) {
  if (Pass > 0)
    ThunkSections.clear();

  // Create all the Thunks and insert them into synthetic ThunkSections. The
  // ThunkSections are later inserted back into the OutputSection.

  // We separate the creation of ThunkSections from the insertion of the
  // ThunkSections back into the OutputSection as ThunkSections are not always
  // inserted into the same OutputSection as the caller.
      OutputSections, [&](OutputSection *OS,  std::vector<InputSection*> *ISR,
        for (Relocation &Rel : IS->Relocations) {
          SymbolBody &Body = *Rel.Sym;
          if (Thunks.find(&Body) != Thunks.end() ||
              !Target->needsThunk(Rel.Expr, Rel.Type, IS->File, Body))
            continue;
          Thunk *T;
          bool IsNew;
          std::tie(T, IsNew) = getThunk(Body, Rel.Type);
          if (IsNew) {
            // Find or create a ThunkSection for the new Thunk
            ThunkSection *TS;
            if (auto *TIS = T->getTargetInputSection())
              TS = getISThunkSec(TIS, OS);
            else
              TS = getOSThunkSec(OS, ISR);
            Thunks[T->ThunkSym] = T;
          }
          // Redirect relocation to Thunk, we never go via the PLT to a Thunk
          Rel.Sym = T->ThunkSym;
          Rel.Expr = fromPlt(Rel.Expr);
  // Merge all created synthetic ThunkSections back into OutputSection
  return !ThunkSections.empty();
template void elf::scanRelocations<ELF32LE>(InputSectionBase &);
template void elf::scanRelocations<ELF32BE>(InputSectionBase &);
template void elf::scanRelocations<ELF64LE>(InputSectionBase &);
template void elf::scanRelocations<ELF64BE>(InputSectionBase &);