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 "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, Triple TT,
41                        LinkGraph::GetEdgeKindNameFunction GetEdgeKindName);
42 
43   LinkGraph &getGraph() const { return *G; }
44 
45   const object::COFFObjectFile &getObject() const { return Obj; }
46 
47   virtual Error addRelocations() = 0;
48 
49   Error graphifySections();
50   Error graphifySymbols();
51 
52   void setGraphSymbol(COFFSectionIndex SecIndex, COFFSymbolIndex SymIndex,
53                       Symbol &Sym) {
54     assert(!GraphSymbols[SymIndex] && "Duplicate symbol at index");
55     GraphSymbols[SymIndex] = &Sym;
56     if (!COFF::isReservedSectionNumber(SecIndex))
57       SymbolSets[SecIndex].insert({Sym.getOffset(), &Sym});
58   }
59 
60   Symbol *getGraphSymbol(COFFSymbolIndex SymIndex) const {
61     if (SymIndex < 0 ||
62         SymIndex >= static_cast<COFFSymbolIndex>(GraphSymbols.size()))
63       return nullptr;
64     return GraphSymbols[SymIndex];
65   }
66 
67   void setGraphBlock(COFFSectionIndex SecIndex, Block *B) {
68     assert(!GraphBlocks[SecIndex] && "Duplicate section at index");
69     assert(!COFF::isReservedSectionNumber(SecIndex) && "Invalid section index");
70     GraphBlocks[SecIndex] = B;
71   }
72 
73   Block *getGraphBlock(COFFSectionIndex SecIndex) const {
74     if (SecIndex <= 0 ||
75         SecIndex >= static_cast<COFFSectionIndex>(GraphSymbols.size()))
76       return nullptr;
77     return GraphBlocks[SecIndex];
78   }
79 
80   object::COFFObjectFile::section_iterator_range sections() const {
81     return Obj.sections();
82   }
83 
84   /// Traverse all matching relocation records in the given section. The handler
85   /// function Func should be callable with this signature:
86   ///   Error(const object::RelocationRef&,
87   ///         const object::SectionRef&, Section &)
88   ///
89   template <typename RelocHandlerFunction>
90   Error forEachRelocation(const object::SectionRef &RelSec,
91                           RelocHandlerFunction &&Func,
92                           bool ProcessDebugSections = false);
93 
94   /// Traverse all matching relocation records in the given section. Convenience
95   /// wrapper to allow passing a member function for the handler.
96   ///
97   template <typename ClassT, typename RelocHandlerMethod>
98   Error forEachRelocation(const object::SectionRef &RelSec, ClassT *Instance,
99                           RelocHandlerMethod &&Method,
100                           bool ProcessDebugSections = false) {
101     return forEachRelocation(
102         RelSec,
103         [Instance, Method](const auto &Rel, const auto &Target, auto &GS) {
104           return (Instance->*Method)(Rel, Target, GS);
105         },
106         ProcessDebugSections);
107   }
108 
109 private:
110   // Pending comdat symbol export that is initiated by the first symbol of
111   // COMDAT sequence.
112   struct ComdatExportRequest {
113     COFFSymbolIndex SymbolIndex;
114     jitlink::Linkage Linkage;
115   };
116   std::vector<Optional<ComdatExportRequest>> PendingComdatExports;
117 
118   // This represents a pending request to create a weak external symbol with a
119   // name.
120   struct WeakExternalRequest {
121     COFFSymbolIndex Alias;
122     COFFSymbolIndex Target;
123     uint32_t Characteristics;
124     StringRef SymbolName;
125   };
126   std::vector<WeakExternalRequest> WeakExternalRequests;
127 
128   // Per COFF section jitlink symbol set sorted by offset.
129   // Used for calculating implicit size of defined symbols.
130   using SymbolSet = std::set<std::pair<orc::ExecutorAddrDiff, Symbol *>>;
131   std::vector<SymbolSet> SymbolSets;
132 
133   Section &getCommonSection();
134 
135   Expected<Symbol *> createDefinedSymbol(COFFSymbolIndex SymIndex,
136                                          StringRef SymbolName,
137                                          object::COFFSymbolRef Symbol,
138                                          const object::coff_section *Section);
139   Expected<Symbol *> createCOMDATExportRequest(
140       COFFSymbolIndex SymIndex, object::COFFSymbolRef Symbol,
141       const object::coff_aux_section_definition *Definition);
142   Expected<Symbol *> exportCOMDATSymbol(COFFSymbolIndex SymIndex,
143                                         StringRef SymbolName,
144                                         object::COFFSymbolRef Symbol);
145   Error flushWeakAliasRequests();
146   Error calculateImplicitSizeOfSymbols();
147 
148   static uint64_t getSectionAddress(const object::COFFObjectFile &Obj,
149                                     const object::coff_section *Section);
150   static uint64_t getSectionSize(const object::COFFObjectFile &Obj,
151                                  const object::coff_section *Section);
152   static bool isComdatSection(const object::coff_section *Section);
153   static unsigned getPointerSize(const object::COFFObjectFile &Obj);
154   static support::endianness getEndianness(const object::COFFObjectFile &Obj);
155   StringRef getCOFFSectionName(COFFSectionIndex SectionIndex,
156                                const object::coff_section *Sec,
157                                object::COFFSymbolRef Sym);
158 
159   const object::COFFObjectFile &Obj;
160   std::unique_ptr<LinkGraph> G;
161 
162   Section *CommonSection = nullptr;
163   std::vector<Block *> GraphBlocks;
164   std::vector<Symbol *> GraphSymbols;
165 
166   DenseMap<StringRef, Symbol *> ExternalSymbols;
167 };
168 
169 template <typename RelocHandlerFunction>
170 Error COFFLinkGraphBuilder::forEachRelocation(const object::SectionRef &RelSec,
171                                               RelocHandlerFunction &&Func,
172                                               bool ProcessDebugSections) {
173 
174   auto COFFRelSect = Obj.getCOFFSection(RelSec);
175 
176   // Target sections have names in valid COFF object files.
177   Expected<StringRef> Name = Obj.getSectionName(COFFRelSect);
178   if (!Name)
179     return Name.takeError();
180   LLVM_DEBUG(dbgs() << "  " << *Name << ":\n");
181 
182   // Lookup the link-graph node corresponding to the target section name.
183   auto *BlockToFix = getGraphBlock(RelSec.getIndex() + 1);
184   if (!BlockToFix)
185     return make_error<StringError>(
186         "Referencing a section that wasn't added to the graph: " + *Name,
187         inconvertibleErrorCode());
188 
189   // Let the callee process relocation entries one by one.
190   for (const auto &R : RelSec.relocations())
191     if (Error Err = Func(R, RelSec, *BlockToFix))
192       return Err;
193 
194   LLVM_DEBUG(dbgs() << "\n");
195   return Error::success();
196 }
197 
198 } // end namespace jitlink
199 } // end namespace llvm
200 
201 #endif // LIB_EXECUTIONENGINE_JITLINK_COFFLINKGRAPHBUILDER_H
202