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