xref: /llvm-project/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h (revision 4e668d5b27a339918bee4d994fca31d962519e80)
1 //===-- RuntimeDyldELF.h - Run-time dynamic linker for MC-JIT ---*- C++ -*-===//
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 // ELF support for MC-JIT runtime dynamic linker.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDELF_H
14 #define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDELF_H
15 
16 #include "RuntimeDyldImpl.h"
17 #include "llvm/ADT/DenseMap.h"
18 
19 namespace llvm {
20 namespace object {
21 class ELFObjectFileBase;
22 }
23 
24 class RuntimeDyldELF : public RuntimeDyldImpl {
25 
26   void resolveRelocation(const SectionEntry &Section, uint64_t Offset,
27                          uint64_t Value, uint32_t Type, int64_t Addend,
28                          uint64_t SymOffset = 0, SID SectionID = 0);
29 
30   void resolveX86_64Relocation(const SectionEntry &Section, uint64_t Offset,
31                                uint64_t Value, uint32_t Type, int64_t Addend,
32                                uint64_t SymOffset);
33 
34   void resolveX86Relocation(const SectionEntry &Section, uint64_t Offset,
35                             uint32_t Value, uint32_t Type, int32_t Addend);
36 
37   void resolveAArch64Relocation(const SectionEntry &Section, uint64_t Offset,
38                                 uint64_t Value, uint32_t Type, int64_t Addend);
39 
40   bool resolveAArch64ShortBranch(unsigned SectionID, relocation_iterator RelI,
41                                  const RelocationValueRef &Value);
42 
43   void resolveAArch64Branch(unsigned SectionID, const RelocationValueRef &Value,
44                             relocation_iterator RelI, StubMap &Stubs);
45 
46   void resolveARMRelocation(const SectionEntry &Section, uint64_t Offset,
47                             uint32_t Value, uint32_t Type, int32_t Addend);
48 
49   void resolveLoongArch64Relocation(const SectionEntry &Section,
50                                     uint64_t Offset, uint64_t Value,
51                                     uint32_t Type, int64_t Addend);
52 
53   bool resolveLoongArch64ShortBranch(unsigned SectionID,
54                                      relocation_iterator RelI,
55                                      const RelocationValueRef &Value);
56 
57   void resolveLoongArch64Branch(unsigned SectionID,
58                                 const RelocationValueRef &Value,
59                                 relocation_iterator RelI, StubMap &Stubs);
60 
61   void resolvePPC32Relocation(const SectionEntry &Section, uint64_t Offset,
62                               uint64_t Value, uint32_t Type, int64_t Addend);
63 
64   void resolvePPC64Relocation(const SectionEntry &Section, uint64_t Offset,
65                               uint64_t Value, uint32_t Type, int64_t Addend);
66 
67   void resolveSystemZRelocation(const SectionEntry &Section, uint64_t Offset,
68                                 uint64_t Value, uint32_t Type, int64_t Addend);
69 
70   void resolveBPFRelocation(const SectionEntry &Section, uint64_t Offset,
71                             uint64_t Value, uint32_t Type, int64_t Addend);
72 
73   void resolveRISCVRelocation(const SectionEntry &Section, uint64_t Offset,
74                               uint64_t Value, uint32_t Type, int64_t Addend,
75                               SID SectionID);
76 
77   unsigned getMaxStubSize() const override {
78     if (Arch == Triple::aarch64 || Arch == Triple::aarch64_be)
79       return 20; // movz; movk; movk; movk; br
80     if (Arch == Triple::arm || Arch == Triple::thumb)
81       return 8; // 32-bit instruction and 32-bit address
82     else if (IsMipsO32ABI || IsMipsN32ABI)
83       return 16;
84     else if (IsMipsN64ABI)
85       return 32;
86     if (Arch == Triple::loongarch64)
87       return 20; // lu12i.w; ori; lu32i.d; lu52i.d; jr
88     else if (Arch == Triple::ppc64 || Arch == Triple::ppc64le)
89       return 44;
90     else if (Arch == Triple::x86_64)
91       return 6; // 2-byte jmp instruction + 32-bit relative address
92     else if (Arch == Triple::systemz)
93       return 16;
94     else
95       return 0;
96   }
97 
98   Align getStubAlignment() override {
99     if (Arch == Triple::systemz)
100       return Align(8);
101     else
102       return Align(1);
103   }
104 
105   void setMipsABI(const ObjectFile &Obj) override;
106 
107   Error findPPC64TOCSection(const object::ELFObjectFileBase &Obj,
108                             ObjSectionToIDMap &LocalSections,
109                             RelocationValueRef &Rel);
110   Error findOPDEntrySection(const object::ELFObjectFileBase &Obj,
111                             ObjSectionToIDMap &LocalSections,
112                             RelocationValueRef &Rel);
113 
114 protected:
115   size_t getGOTEntrySize() override;
116 
117 private:
118   SectionEntry &getSection(unsigned SectionID) { return Sections[SectionID]; }
119 
120   // Allocate no GOT entries for use in the given section.
121   uint64_t allocateGOTEntries(unsigned no);
122 
123   // Find GOT entry corresponding to relocation or create new one.
124   uint64_t findOrAllocGOTEntry(const RelocationValueRef &Value,
125                                unsigned GOTRelType);
126 
127   // Resolve the relative address of GOTOffset in Section ID and place
128   // it at the given Offset
129   void resolveGOTOffsetRelocation(unsigned SectionID, uint64_t Offset,
130                                   uint64_t GOTOffset, uint32_t Type);
131 
132   // For a GOT entry referenced from SectionID, compute a relocation entry
133   // that will place the final resolved value in the GOT slot
134   RelocationEntry computeGOTOffsetRE(uint64_t GOTOffset, uint64_t SymbolOffset,
135                                      unsigned Type);
136 
137   // Compute the address in memory where we can find the placeholder
138   void *computePlaceholderAddress(unsigned SectionID, uint64_t Offset) const;
139 
140   // Split out common case for creating the RelocationEntry for when the
141   // relocation requires no particular advanced processing.
142   void processSimpleRelocation(unsigned SectionID, uint64_t Offset, unsigned RelType, RelocationValueRef Value);
143 
144   // Return matching *LO16 relocation (Mips specific)
145   uint32_t getMatchingLoRelocation(uint32_t RelType,
146                                    bool IsLocal = false) const;
147 
148   // The tentative ID for the GOT section
149   unsigned GOTSectionID;
150 
151   // Records the current number of allocated slots in the GOT
152   // (This would be equivalent to GOTEntries.size() were it not for relocations
153   // that consume more than one slot)
154   unsigned CurrentGOTIndex;
155 
156 protected:
157   // A map from section to a GOT section that has entries for section's GOT
158   // relocations. (Mips64 specific)
159   DenseMap<SID, SID> SectionToGOTMap;
160 
161 private:
162   // A map to avoid duplicate got entries (Mips64 specific)
163   StringMap<uint64_t> GOTSymbolOffsets;
164 
165   // *HI16 relocations will be added for resolving when we find matching
166   // *LO16 part. (Mips specific)
167   //
168   // *HI20 relocations will be added for resolving when we find matching
169   // *LO12 part. (RISC-V specific)
170   SmallVector<std::pair<RelocationValueRef, RelocationEntry>, 8> PendingRelocs;
171 
172   // When a module is loaded we save the SectionID of the EH frame section
173   // in a table until we receive a request to register all unregistered
174   // EH frame sections with the memory manager.
175   SmallVector<SID, 2> UnregisteredEHFrameSections;
176 
177   // Map between GOT relocation value and corresponding GOT offset
178   std::map<RelocationValueRef, uint64_t> GOTOffsetMap;
179 
180   /// The ID of the current IFunc stub section
181   unsigned IFuncStubSectionID = 0;
182   /// The current offset into the IFunc stub section
183   uint64_t IFuncStubOffset = 0;
184 
185   /// A IFunc stub and its original symbol
186   struct IFuncStub {
187     /// The offset of this stub in the IFunc stub section
188     uint64_t StubOffset;
189     /// The symbol table entry of the original symbol
190     SymbolTableEntry OriginalSymbol;
191   };
192 
193   /// The IFunc stubs
194   SmallVector<IFuncStub, 2> IFuncStubs;
195 
196   /// Create the code for the IFunc resolver at the given address. This code
197   /// works together with the stubs created in createIFuncStub() to call the
198   /// resolver function and then jump to the real function address.
199   /// It must not be larger than 64B.
200   void createIFuncResolver(uint8_t *Addr) const;
201   /// Create the code for an IFunc stub for the IFunc that is defined in
202   /// section IFuncSectionID at offset IFuncOffset. The IFunc resolver created
203   /// by createIFuncResolver() is defined in the section IFuncStubSectionID at
204   /// offset IFuncResolverOffset. The code should be written into the section
205   /// with the id IFuncStubSectionID at the offset IFuncStubOffset.
206   void createIFuncStub(unsigned IFuncStubSectionID,
207                        uint64_t IFuncResolverOffset, uint64_t IFuncStubOffset,
208                        unsigned IFuncSectionID, uint64_t IFuncOffset);
209   /// Return the maximum size of a stub created by createIFuncStub()
210   unsigned getMaxIFuncStubSize() const;
211 
212   void processNewSymbol(const SymbolRef &ObjSymbol,
213                         SymbolTableEntry &Entry) override;
214   bool relocationNeedsGot(const RelocationRef &R) const override;
215   bool relocationNeedsStub(const RelocationRef &R) const override;
216 
217   // Process a GOTTPOFF TLS relocation for x86-64
218   // NOLINTNEXTLINE(readability-identifier-naming)
219   void processX86_64GOTTPOFFRelocation(unsigned SectionID, uint64_t Offset,
220                                        RelocationValueRef Value,
221                                        int64_t Addend);
222   // Process a TLSLD/TLSGD relocation for x86-64
223   // NOLINTNEXTLINE(readability-identifier-naming)
224   void processX86_64TLSRelocation(unsigned SectionID, uint64_t Offset,
225                                   uint64_t RelType, RelocationValueRef Value,
226                                   int64_t Addend,
227                                   const RelocationRef &GetAddrRelocation);
228 
229 public:
230   RuntimeDyldELF(RuntimeDyld::MemoryManager &MemMgr,
231                  JITSymbolResolver &Resolver);
232   ~RuntimeDyldELF() override;
233 
234   static std::unique_ptr<RuntimeDyldELF>
235   create(Triple::ArchType Arch, RuntimeDyld::MemoryManager &MemMgr,
236          JITSymbolResolver &Resolver);
237 
238   std::unique_ptr<RuntimeDyld::LoadedObjectInfo>
239   loadObject(const object::ObjectFile &O) override;
240 
241   void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override;
242   Expected<relocation_iterator>
243   processRelocationRef(unsigned SectionID, relocation_iterator RelI,
244                        const ObjectFile &Obj,
245                        ObjSectionToIDMap &ObjSectionToID,
246                        StubMap &Stubs) override;
247   bool isCompatibleFile(const object::ObjectFile &Obj) const override;
248   void registerEHFrames() override;
249   Error finalizeLoad(const ObjectFile &Obj,
250                      ObjSectionToIDMap &SectionMap) override;
251 };
252 
253 } // end namespace llvm
254 
255 #endif // LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDELF_H
256