|  | 
|  | 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-exception | 
|  | 6 | +// | 
|  | 7 | +//===----------------------------------------------------------------------===// | 
|  | 8 | + | 
|  | 9 | +#ifndef LLD_ELF_ARCH_TARGETIMPL_H | 
|  | 10 | +#define LLD_ELF_ARCH_TARGETIMPL_H | 
|  | 11 | + | 
|  | 12 | +#include "InputFiles.h" | 
|  | 13 | +#include "InputSection.h" | 
|  | 14 | +#include "Relocations.h" | 
|  | 15 | +#include "Symbols.h" | 
|  | 16 | +#include "llvm/BinaryFormat/ELF.h" | 
|  | 17 | + | 
|  | 18 | +namespace lld::elf { | 
|  | 19 | + | 
|  | 20 | +// getControlTransferAddend: If this relocation is used for control transfer | 
|  | 21 | +// 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 return | 
|  | 24 | +// std::nullopt. The effective addend for a relocation is the addend that is | 
|  | 25 | +// used to determine its branch destination. | 
|  | 26 | +// | 
|  | 27 | +// getBranchInfoAtTarget: If a control transfer relocation referring to | 
|  | 28 | +// is+offset directly transfers control to a relocated branch instruction in the | 
|  | 29 | +// specified section, return the relocation for the branch target as well as its | 
|  | 30 | +// effective addend (see above). Otherwise return {nullptr, 0}. | 
|  | 31 | +// | 
|  | 32 | +// redirectControlTransferRelocations: Given r1, a relocation for which | 
|  | 33 | +// getControlTransferAddend() returned a value, and r2, a relocation returned by | 
|  | 34 | +// getBranchInfo(), modify r1 so that it branches directly to the target of r2. | 
|  | 35 | +template <typename GetControlTransferAddend, typename GetBranchInfoAtTarget, | 
|  | 36 | +          typename RedirectControlTransferRelocations> | 
|  | 37 | +inline 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 as | 
|  | 42 | +  // 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 writable | 
|  | 51 | +      // 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 *s : f->getSections()) { | 
|  | 62 | +      if (!s) | 
|  | 63 | +        continue; | 
|  | 64 | +      for (Relocation &r : s->relocations) { | 
|  | 65 | +        std::optional<uint64_t> addend = | 
|  | 66 | +            getControlTransferAddend(*cast<InputSection>(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 branch | 
|  | 74 | +        // that (possibly indirectly) branches to itself. It is unlikely | 
|  | 75 | +        // 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::elf | 
|  | 92 | + | 
|  | 93 | +#endif | 
0 commit comments