brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.0 KiB · 90a2b53 Raw
94 lines · c
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLD_ELF_ARCH_TARGETIMPL_H10#define LLD_ELF_ARCH_TARGETIMPL_H11 12#include "InputFiles.h"13#include "InputSection.h"14#include "Relocations.h"15#include "Symbols.h"16#include "llvm/BinaryFormat/ELF.h"17 18namespace lld::elf {19 20// getControlTransferAddend: If this relocation is used for control transfer21// instructions (e.g. branch, branch-link or call) or code references (e.g.22// virtual function pointers) and indicates an address-insignificant reference,23// return the effective addend for the relocation, otherwise return24// std::nullopt. The effective addend for a relocation is the addend that is25// used to determine its branch destination.26//27// getBranchInfoAtTarget: If a control transfer relocation referring to28// is+offset directly transfers control to a relocated branch instruction in the29// specified section, return the relocation for the branch target as well as its30// effective addend (see above). Otherwise return {nullptr, 0}.31//32// redirectControlTransferRelocations: Given r1, a relocation for which33// getControlTransferAddend() returned a value, and r2, a relocation returned by34// getBranchInfo(), modify r1 so that it branches directly to the target of r2.35template <typename GetControlTransferAddend, typename GetBranchInfoAtTarget,36          typename RedirectControlTransferRelocations>37inline void applyBranchToBranchOptImpl(38    Ctx &ctx, GetControlTransferAddend getControlTransferAddend,39    GetBranchInfoAtTarget getBranchInfoAtTarget,40    RedirectControlTransferRelocations redirectControlTransferRelocations) {41  // Needs to run serially because it writes to the relocations array as well as42  // reading relocations of other sections.43  for (ELFFileBase *f : ctx.objectFiles) {44    auto getRelocBranchInfo =45        [&getBranchInfoAtTarget](46            Relocation &r,47            uint64_t addend) -> std::pair<Relocation *, uint64_t> {48      auto *target = dyn_cast_or_null<Defined>(r.sym);49      // We don't allow preemptible symbols or ifuncs (may go somewhere else),50      // absolute symbols (runtime behavior unknown), non-executable or writable51      // memory (ditto) or non-regular sections (no section data).52      if (!target || target->isPreemptible || target->isGnuIFunc() ||53          !target->section ||54          !(target->section->flags & llvm::ELF::SHF_EXECINSTR) ||55          (target->section->flags & llvm::ELF::SHF_WRITE) ||56          target->section->kind() != SectionBase::Regular)57        return {nullptr, 0};58      return getBranchInfoAtTarget(*cast<InputSection>(target->section),59                                   target->value + addend);60    };61    for (InputSectionBase *sb : f->getSections()) {62      auto *s = dyn_cast_or_null<InputSection>(sb);63      if (!s)64        continue;65      for (Relocation &r : s->relocations) {66        std::optional<uint64_t> addend = getControlTransferAddend(*s, r);67        if (!addend)68          continue;69        std::pair<Relocation *, uint64_t> targetAndAddend =70            getRelocBranchInfo(r, *addend);71        if (!targetAndAddend.first)72          continue;73        // Avoid getting stuck in an infinite loop if we encounter a branch74        // that (possibly indirectly) branches to itself. It is unlikely75        // that more than 5 iterations will ever be needed in practice.76        size_t iterations = 5;77        while (iterations--) {78          std::pair<Relocation *, uint64_t> nextTargetAndAddend =79              getRelocBranchInfo(*targetAndAddend.first,80                                 targetAndAddend.second);81          if (!nextTargetAndAddend.first)82            break;83          targetAndAddend = nextTargetAndAddend;84        }85        redirectControlTransferRelocations(r, *targetAndAddend.first);86      }87    }88  }89}90 91} // namespace lld::elf92 93#endif94