xref: /llvm-project/llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.h (revision 98be16f20f3f0e2ca6f3cf34fe9da25822c21c2d)
1 //===----- COFFLinkGraphBuilder.h - COFF LinkGraph builder ----*- 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 // Generic COFF LinkGraph building code.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LIB_EXECUTIONENGINE_JITLINK_COFFLINKGRAPHBUILDER_H
14 #define LIB_EXECUTIONENGINE_JITLINK_COFFLINKGRAPHBUILDER_H
15 
16 #include "llvm/ADT/DenseMap.h"
17 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
18 #include "llvm/Object/COFF.h"
19 
20 #include "COFFDirectiveParser.h"
21 #include "EHFrameSupportImpl.h"
22 #include "JITLinkGeneric.h"
23 
24 #define DEBUG_TYPE "jitlink"
25 
26 #include <list>
27 
28 namespace llvm {
29 namespace jitlink {
30 
31 class COFFLinkGraphBuilder {
32 public:
33   virtual ~COFFLinkGraphBuilder();
34   Expected<std::unique_ptr<LinkGraph>> buildGraph();
35 
36 protected:
37   using COFFSectionIndex = int32_t;
38   using COFFSymbolIndex = int32_t;
39 
40   COFFLinkGraphBuilder(const object::COFFObjectFile &Obj,
41                        std::shared_ptr<orc::SymbolStringPool> SSP, Triple TT,
42                        SubtargetFeatures Features,
43                        LinkGraph::GetEdgeKindNameFunction GetEdgeKindName);
44 
45   LinkGraph &getGraph() const { return *G; }
46 
47   const object::COFFObjectFile &getObject() const { return Obj; }
48 
49   virtual Error addRelocations() = 0;
50 
51   Error graphifySections();
52   Error graphifySymbols();
53 
54   void setGraphSymbol(COFFSectionIndex SecIndex, COFFSymbolIndex SymIndex,
55                       Symbol &Sym) {
56     assert(!GraphSymbols[SymIndex] && "Duplicate symbol at index");
57     GraphSymbols[SymIndex] = &Sym;
58     if (!COFF::isReservedSectionNumber(SecIndex))
59       SymbolSets[SecIndex].insert({Sym.getOffset(), &Sym});
60   }
61 
62   Symbol *getGraphSymbol(COFFSymbolIndex SymIndex) const {
63     if (SymIndex < 0 ||
64         SymIndex >= static_cast<COFFSymbolIndex>(GraphSymbols.size()))
65       return nullptr;
66     return GraphSymbols[SymIndex];
67   }
68 
69   void setGraphBlock(COFFSectionIndex SecIndex, Block *B) {
70     assert(!GraphBlocks[SecIndex] && "Duplicate section at index");
71     assert(!COFF::isReservedSectionNumber(SecIndex) && "Invalid section index");
72     GraphBlocks[SecIndex] = B;
73   }
74 
75   Block *getGraphBlock(COFFSectionIndex SecIndex) const {
76     if (SecIndex <= 0 ||
77         SecIndex >= static_cast<COFFSectionIndex>(GraphSymbols.size()))
78       return nullptr;
79     return GraphBlocks[SecIndex];
80   }
81 
82   Symbol &addImageBaseSymbol(StringRef Name = "__ImageBase") {
83     auto &ImageBase = G->addExternalSymbol(G->intern(Name), 0, true);
84     ImageBase.setLive(true);
85     return ImageBase;
86   }
87 
88   object::COFFObjectFile::section_iterator_range sections() const {
89     return Obj.sections();
90   }
91 
92   /// Traverse all matching relocation records in the given section. The handler
93   /// function Func should be callable with this signature:
94   ///   Error(const object::RelocationRef&,
95   ///         const object::SectionRef&, Section &)
96   ///
97   template <typename RelocHandlerFunction>
98   Error forEachRelocation(const object::SectionRef &RelSec,
99                           RelocHandlerFunction &&Func,
100                           bool ProcessDebugSections = false);
101 
102   /// Traverse all matching relocation records in the given section. Convenience
103   /// wrapper to allow passing a member function for the handler.
104   ///
105   template <typename ClassT, typename RelocHandlerMethod>
106   Error forEachRelocation(const object::SectionRef &RelSec, ClassT *Instance,
107                           RelocHandlerMethod &&Method,
108                           bool ProcessDebugSections = false) {
109     return forEachRelocation(
110         RelSec,
111         [Instance, Method](const auto &Rel, const auto &Target, auto &GS) {
112           return (Instance->*Method)(Rel, Target, GS);
113         },
114         ProcessDebugSections);
115   }
116 
117 private:
118   // Pending comdat symbol export that is initiated by the first symbol of
119   // COMDAT sequence.
120   struct ComdatExportRequest {
121     COFFSymbolIndex SymbolIndex;
122     jitlink::Linkage Linkage;
123     orc::ExecutorAddrDiff Size;
124   };
125   std::vector<std::optional<ComdatExportRequest>> PendingComdatExports;
126 
127   // This represents a pending request to create a weak external symbol with a
128   // name.
129   struct WeakExternalRequest {
130     COFFSymbolIndex Alias;
131     COFFSymbolIndex Target;
132     uint32_t Characteristics;
133     StringRef SymbolName;
134   };
135   std::vector<WeakExternalRequest> WeakExternalRequests;
136 
137   // Per COFF section jitlink symbol set sorted by offset.
138   // Used for calculating implicit size of defined symbols.
139   using SymbolSet = std::set<std::pair<orc::ExecutorAddrDiff, Symbol *>>;
140   std::vector<SymbolSet> SymbolSets;
141 
142   Section &getCommonSection();
143 
144   Symbol *createExternalSymbol(COFFSymbolIndex SymIndex,
145                                orc::SymbolStringPtr SymbolName,
146                                object::COFFSymbolRef Symbol,
147                                const object::coff_section *Section);
148   Expected<Symbol *> createAliasSymbol(orc::SymbolStringPtr SymbolName,
149                                        Linkage L, Scope S, Symbol &Target);
150   Expected<Symbol *> createDefinedSymbol(COFFSymbolIndex SymIndex,
151                                          orc::SymbolStringPtr SymbolName,
152                                          object::COFFSymbolRef Symbol,
153                                          const object::coff_section *Section);
154   Expected<Symbol *> createCOMDATExportRequest(
155       COFFSymbolIndex SymIndex, object::COFFSymbolRef Symbol,
156       const object::coff_aux_section_definition *Definition);
157   Expected<Symbol *> exportCOMDATSymbol(COFFSymbolIndex SymIndex,
158                                         orc::SymbolStringPtr SymbolName,
159                                         object::COFFSymbolRef Symbol);
160 
161   Error handleDirectiveSection(StringRef Str);
162   Error flushWeakAliasRequests();
163   Error handleAlternateNames();
164   Error calculateImplicitSizeOfSymbols();
165 
166   static uint64_t getSectionAddress(const object::COFFObjectFile &Obj,
167                                     const object::coff_section *Section);
168   static uint64_t getSectionSize(const object::COFFObjectFile &Obj,
169                                  const object::coff_section *Section);
170   static bool isComdatSection(const object::coff_section *Section);
171   static unsigned getPointerSize(const object::COFFObjectFile &Obj);
172   static llvm::endianness getEndianness(const object::COFFObjectFile &Obj);
173   static StringRef getDLLImportStubPrefix() { return "__imp_"; }
174   static StringRef getDirectiveSectionName() { return ".drectve"; }
175   StringRef getCOFFSectionName(COFFSectionIndex SectionIndex,
176                                const object::coff_section *Sec,
177                                object::COFFSymbolRef Sym);
178 
179   const object::COFFObjectFile &Obj;
180   std::unique_ptr<LinkGraph> G;
181   COFFDirectiveParser DirectiveParser;
182 
183   Section *CommonSection = nullptr;
184   std::vector<Block *> GraphBlocks;
185   std::vector<Symbol *> GraphSymbols;
186 
187   DenseMap<orc::SymbolStringPtr, orc::SymbolStringPtr> AlternateNames;
188   DenseMap<orc::SymbolStringPtr, Symbol *> ExternalSymbols;
189   DenseMap<orc::SymbolStringPtr, Symbol *> DefinedSymbols;
190 };
191 
192 template <typename RelocHandlerFunction>
193 Error COFFLinkGraphBuilder::forEachRelocation(const object::SectionRef &RelSec,
194                                               RelocHandlerFunction &&Func,
195                                               bool ProcessDebugSections) {
196 
197   auto COFFRelSect = Obj.getCOFFSection(RelSec);
198 
199   // Target sections have names in valid COFF object files.
200   Expected<StringRef> Name = Obj.getSectionName(COFFRelSect);
201   if (!Name)
202     return Name.takeError();
203 
204   // Skip the unhandled metadata sections.
205   if (*Name == ".voltbl")
206     return Error::success();
207   LLVM_DEBUG(dbgs() << "  " << *Name << ":\n");
208 
209   // Lookup the link-graph node corresponding to the target section name.
210   auto *BlockToFix = getGraphBlock(RelSec.getIndex() + 1);
211   if (!BlockToFix)
212     return make_error<StringError>(
213         "Referencing a section that wasn't added to the graph: " + *Name,
214         inconvertibleErrorCode());
215 
216   // Let the callee process relocation entries one by one.
217   for (const auto &R : RelSec.relocations())
218     if (Error Err = Func(R, RelSec, *BlockToFix))
219       return Err;
220 
221   LLVM_DEBUG(dbgs() << "\n");
222   return Error::success();
223 }
224 
225 class GetImageBaseSymbol {
226 public:
227   GetImageBaseSymbol(StringRef ImageBaseName = "__ImageBase")
228       : ImageBaseName(ImageBaseName) {}
229   Symbol *operator()(LinkGraph &G);
230   void reset() { ImageBase = std::nullopt; }
231 
232 private:
233   StringRef ImageBaseName;
234   std::optional<Symbol *> ImageBase;
235 };
236 
237 } // end namespace jitlink
238 } // end namespace llvm
239 
240 #endif // LIB_EXECUTIONENGINE_JITLINK_COFFLINKGRAPHBUILDER_H
241