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