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/ADT/StringMap.h"
18 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
19 #include "llvm/Object/COFF.h"
20 
21 #include "COFFDirectiveParser.h"
22 #include "EHFrameSupportImpl.h"
23 #include "JITLinkGeneric.h"
24 
25 #define DEBUG_TYPE "jitlink"
26 
27 #include <list>
28 
29 namespace llvm {
30 namespace jitlink {
31 
32 class COFFLinkGraphBuilder {
33 public:
34   virtual ~COFFLinkGraphBuilder();
35   Expected<std::unique_ptr<LinkGraph>> buildGraph();
36 
37 protected:
38   using COFFSectionIndex = int32_t;
39   using COFFSymbolIndex = int32_t;
40 
41   COFFLinkGraphBuilder(const object::COFFObjectFile &Obj, 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   object::COFFObjectFile::section_iterator_range sections() const {
83     return Obj.sections();
84   }
85 
86   /// Traverse all matching relocation records in the given section. The handler
87   /// function Func should be callable with this signature:
88   ///   Error(const object::RelocationRef&,
89   ///         const object::SectionRef&, Section &)
90   ///
91   template <typename RelocHandlerFunction>
92   Error forEachRelocation(const object::SectionRef &RelSec,
93                           RelocHandlerFunction &&Func,
94                           bool ProcessDebugSections = false);
95 
96   /// Traverse all matching relocation records in the given section. Convenience
97   /// wrapper to allow passing a member function for the handler.
98   ///
99   template <typename ClassT, typename RelocHandlerMethod>
100   Error forEachRelocation(const object::SectionRef &RelSec, ClassT *Instance,
101                           RelocHandlerMethod &&Method,
102                           bool ProcessDebugSections = false) {
103     return forEachRelocation(
104         RelSec,
105         [Instance, Method](const auto &Rel, const auto &Target, auto &GS) {
106           return (Instance->*Method)(Rel, Target, GS);
107         },
108         ProcessDebugSections);
109   }
110 
111 private:
112   // Pending comdat symbol export that is initiated by the first symbol of
113   // COMDAT sequence.
114   struct ComdatExportRequest {
115     COFFSymbolIndex SymbolIndex;
116     jitlink::Linkage Linkage;
117     orc::ExecutorAddrDiff Size;
118   };
119   std::vector<std::optional<ComdatExportRequest>> PendingComdatExports;
120 
121   // This represents a pending request to create a weak external symbol with a
122   // name.
123   struct WeakExternalRequest {
124     COFFSymbolIndex Alias;
125     COFFSymbolIndex Target;
126     uint32_t Characteristics;
127     StringRef SymbolName;
128   };
129   std::vector<WeakExternalRequest> WeakExternalRequests;
130 
131   // Per COFF section jitlink symbol set sorted by offset.
132   // Used for calculating implicit size of defined symbols.
133   using SymbolSet = std::set<std::pair<orc::ExecutorAddrDiff, Symbol *>>;
134   std::vector<SymbolSet> SymbolSets;
135 
136   Section &getCommonSection();
137 
138   Symbol *createExternalSymbol(COFFSymbolIndex SymIndex, StringRef SymbolName,
139                                object::COFFSymbolRef Symbol,
140                                const object::coff_section *Section);
141   Expected<Symbol *> createAliasSymbol(StringRef SymbolName, Linkage L, Scope S,
142                                        Symbol &Target);
143   Expected<Symbol *> createDefinedSymbol(COFFSymbolIndex SymIndex,
144                                          StringRef SymbolName,
145                                          object::COFFSymbolRef Symbol,
146                                          const object::coff_section *Section);
147   Expected<Symbol *> createCOMDATExportRequest(
148       COFFSymbolIndex SymIndex, object::COFFSymbolRef Symbol,
149       const object::coff_aux_section_definition *Definition);
150   Expected<Symbol *> exportCOMDATSymbol(COFFSymbolIndex SymIndex,
151                                         StringRef SymbolName,
152                                         object::COFFSymbolRef Symbol);
153 
154   Error handleDirectiveSection(StringRef Str);
155   Error flushWeakAliasRequests();
156   Error handleAlternateNames();
157   Error calculateImplicitSizeOfSymbols();
158 
159   static uint64_t getSectionAddress(const object::COFFObjectFile &Obj,
160                                     const object::coff_section *Section);
161   static uint64_t getSectionSize(const object::COFFObjectFile &Obj,
162                                  const object::coff_section *Section);
163   static bool isComdatSection(const object::coff_section *Section);
164   static unsigned getPointerSize(const object::COFFObjectFile &Obj);
165   static support::endianness getEndianness(const object::COFFObjectFile &Obj);
166   static StringRef getDLLImportStubPrefix() { return "__imp_"; }
167   static StringRef getDirectiveSectionName() { return ".drectve"; }
168   StringRef getCOFFSectionName(COFFSectionIndex SectionIndex,
169                                const object::coff_section *Sec,
170                                object::COFFSymbolRef Sym);
171 
172   const object::COFFObjectFile &Obj;
173   std::unique_ptr<LinkGraph> G;
174   COFFDirectiveParser DirectiveParser;
175 
176   Section *CommonSection = nullptr;
177   std::vector<Block *> GraphBlocks;
178   std::vector<Symbol *> GraphSymbols;
179 
180   DenseMap<StringRef, StringRef> AlternateNames;
181   DenseMap<StringRef, Symbol *> ExternalSymbols;
182   DenseMap<StringRef, Symbol *> DefinedSymbols;
183 };
184 
185 template <typename RelocHandlerFunction>
186 Error COFFLinkGraphBuilder::forEachRelocation(const object::SectionRef &RelSec,
187                                               RelocHandlerFunction &&Func,
188                                               bool ProcessDebugSections) {
189 
190   auto COFFRelSect = Obj.getCOFFSection(RelSec);
191 
192   // Target sections have names in valid COFF object files.
193   Expected<StringRef> Name = Obj.getSectionName(COFFRelSect);
194   if (!Name)
195     return Name.takeError();
196 
197   // Skip the unhandled metadata sections.
198   if (*Name == ".voltbl")
199     return Error::success();
200   LLVM_DEBUG(dbgs() << "  " << *Name << ":\n");
201 
202   // Lookup the link-graph node corresponding to the target section name.
203   auto *BlockToFix = getGraphBlock(RelSec.getIndex() + 1);
204   if (!BlockToFix)
205     return make_error<StringError>(
206         "Referencing a section that wasn't added to the graph: " + *Name,
207         inconvertibleErrorCode());
208 
209   // Let the callee process relocation entries one by one.
210   for (const auto &R : RelSec.relocations())
211     if (Error Err = Func(R, RelSec, *BlockToFix))
212       return Err;
213 
214   LLVM_DEBUG(dbgs() << "\n");
215   return Error::success();
216 }
217 
218 } // end namespace jitlink
219 } // end namespace llvm
220 
221 #endif // LIB_EXECUTIONENGINE_JITLINK_COFFLINKGRAPHBUILDER_H
222