xref: /freebsd-src/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.h (revision 972a253a57b6f144b0e4a3e2080a2a0076ec55a0)
1753f127fSDimitry Andric //===----- COFFLinkGraphBuilder.h - COFF LinkGraph builder ----*- C++ -*-===//
2753f127fSDimitry Andric //
3753f127fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4753f127fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5753f127fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6753f127fSDimitry Andric //
7753f127fSDimitry Andric //===----------------------------------------------------------------------===//
8753f127fSDimitry Andric //
9753f127fSDimitry Andric // Generic COFF LinkGraph building code.
10753f127fSDimitry Andric //
11753f127fSDimitry Andric //===----------------------------------------------------------------------===//
12753f127fSDimitry Andric 
13753f127fSDimitry Andric #ifndef LIB_EXECUTIONENGINE_JITLINK_COFFLINKGRAPHBUILDER_H
14753f127fSDimitry Andric #define LIB_EXECUTIONENGINE_JITLINK_COFFLINKGRAPHBUILDER_H
15753f127fSDimitry Andric 
16753f127fSDimitry Andric #include "llvm/ADT/DenseMap.h"
17753f127fSDimitry Andric #include "llvm/ADT/StringMap.h"
18753f127fSDimitry Andric #include "llvm/ExecutionEngine/JITLink/JITLink.h"
19753f127fSDimitry Andric #include "llvm/Object/COFF.h"
20753f127fSDimitry Andric 
21753f127fSDimitry Andric #include "EHFrameSupportImpl.h"
22753f127fSDimitry Andric #include "JITLinkGeneric.h"
23753f127fSDimitry Andric 
24753f127fSDimitry Andric #define DEBUG_TYPE "jitlink"
25753f127fSDimitry Andric 
26753f127fSDimitry Andric #include <list>
27753f127fSDimitry Andric 
28753f127fSDimitry Andric namespace llvm {
29753f127fSDimitry Andric namespace jitlink {
30753f127fSDimitry Andric 
31753f127fSDimitry Andric class COFFLinkGraphBuilder {
32753f127fSDimitry Andric public:
33753f127fSDimitry Andric   virtual ~COFFLinkGraphBuilder();
34753f127fSDimitry Andric   Expected<std::unique_ptr<LinkGraph>> buildGraph();
35753f127fSDimitry Andric 
36753f127fSDimitry Andric protected:
37753f127fSDimitry Andric   using COFFSectionIndex = int32_t;
38753f127fSDimitry Andric   using COFFSymbolIndex = int32_t;
39753f127fSDimitry Andric 
40753f127fSDimitry Andric   COFFLinkGraphBuilder(const object::COFFObjectFile &Obj, Triple TT,
41753f127fSDimitry Andric                        LinkGraph::GetEdgeKindNameFunction GetEdgeKindName);
42753f127fSDimitry Andric 
43753f127fSDimitry Andric   LinkGraph &getGraph() const { return *G; }
44753f127fSDimitry Andric 
45753f127fSDimitry Andric   const object::COFFObjectFile &getObject() const { return Obj; }
46753f127fSDimitry Andric 
47753f127fSDimitry Andric   virtual Error addRelocations() = 0;
48753f127fSDimitry Andric 
49753f127fSDimitry Andric   Error graphifySections();
50753f127fSDimitry Andric   Error graphifySymbols();
51753f127fSDimitry Andric 
52753f127fSDimitry Andric   void setGraphSymbol(COFFSectionIndex SecIndex, COFFSymbolIndex SymIndex,
53753f127fSDimitry Andric                       Symbol &Sym) {
54753f127fSDimitry Andric     assert(!GraphSymbols[SymIndex] && "Duplicate symbol at index");
55753f127fSDimitry Andric     GraphSymbols[SymIndex] = &Sym;
56753f127fSDimitry Andric     if (!COFF::isReservedSectionNumber(SecIndex))
57753f127fSDimitry Andric       SymbolSets[SecIndex].insert({Sym.getOffset(), &Sym});
58753f127fSDimitry Andric   }
59753f127fSDimitry Andric 
60753f127fSDimitry Andric   Symbol *getGraphSymbol(COFFSymbolIndex SymIndex) const {
61753f127fSDimitry Andric     if (SymIndex < 0 ||
62753f127fSDimitry Andric         SymIndex >= static_cast<COFFSymbolIndex>(GraphSymbols.size()))
63753f127fSDimitry Andric       return nullptr;
64753f127fSDimitry Andric     return GraphSymbols[SymIndex];
65753f127fSDimitry Andric   }
66753f127fSDimitry Andric 
67753f127fSDimitry Andric   void setGraphBlock(COFFSectionIndex SecIndex, Block *B) {
68753f127fSDimitry Andric     assert(!GraphBlocks[SecIndex] && "Duplicate section at index");
69753f127fSDimitry Andric     assert(!COFF::isReservedSectionNumber(SecIndex) && "Invalid section index");
70753f127fSDimitry Andric     GraphBlocks[SecIndex] = B;
71753f127fSDimitry Andric   }
72753f127fSDimitry Andric 
73753f127fSDimitry Andric   Block *getGraphBlock(COFFSectionIndex SecIndex) const {
74753f127fSDimitry Andric     if (SecIndex <= 0 ||
75753f127fSDimitry Andric         SecIndex >= static_cast<COFFSectionIndex>(GraphSymbols.size()))
76753f127fSDimitry Andric       return nullptr;
77753f127fSDimitry Andric     return GraphBlocks[SecIndex];
78753f127fSDimitry Andric   }
79753f127fSDimitry Andric 
80753f127fSDimitry Andric   object::COFFObjectFile::section_iterator_range sections() const {
81753f127fSDimitry Andric     return Obj.sections();
82753f127fSDimitry Andric   }
83753f127fSDimitry Andric 
84753f127fSDimitry Andric   /// Traverse all matching relocation records in the given section. The handler
85753f127fSDimitry Andric   /// function Func should be callable with this signature:
86753f127fSDimitry Andric   ///   Error(const object::RelocationRef&,
87753f127fSDimitry Andric   ///         const object::SectionRef&, Section &)
88753f127fSDimitry Andric   ///
89753f127fSDimitry Andric   template <typename RelocHandlerFunction>
90753f127fSDimitry Andric   Error forEachRelocation(const object::SectionRef &RelSec,
91753f127fSDimitry Andric                           RelocHandlerFunction &&Func,
92753f127fSDimitry Andric                           bool ProcessDebugSections = false);
93753f127fSDimitry Andric 
94753f127fSDimitry Andric   /// Traverse all matching relocation records in the given section. Convenience
95753f127fSDimitry Andric   /// wrapper to allow passing a member function for the handler.
96753f127fSDimitry Andric   ///
97753f127fSDimitry Andric   template <typename ClassT, typename RelocHandlerMethod>
98753f127fSDimitry Andric   Error forEachRelocation(const object::SectionRef &RelSec, ClassT *Instance,
99753f127fSDimitry Andric                           RelocHandlerMethod &&Method,
100753f127fSDimitry Andric                           bool ProcessDebugSections = false) {
101753f127fSDimitry Andric     return forEachRelocation(
102753f127fSDimitry Andric         RelSec,
103753f127fSDimitry Andric         [Instance, Method](const auto &Rel, const auto &Target, auto &GS) {
104753f127fSDimitry Andric           return (Instance->*Method)(Rel, Target, GS);
105753f127fSDimitry Andric         },
106753f127fSDimitry Andric         ProcessDebugSections);
107753f127fSDimitry Andric   }
108753f127fSDimitry Andric 
109753f127fSDimitry Andric private:
110753f127fSDimitry Andric   // Pending comdat symbol export that is initiated by the first symbol of
111753f127fSDimitry Andric   // COMDAT sequence.
112753f127fSDimitry Andric   struct ComdatExportRequest {
113753f127fSDimitry Andric     COFFSymbolIndex SymbolIndex;
114753f127fSDimitry Andric     jitlink::Linkage Linkage;
115753f127fSDimitry Andric   };
116*972a253aSDimitry Andric   std::vector<Optional<ComdatExportRequest>> PendingComdatExports;
117753f127fSDimitry Andric 
118753f127fSDimitry Andric   // This represents a pending request to create a weak external symbol with a
119753f127fSDimitry Andric   // name.
120*972a253aSDimitry Andric   struct WeakExternalRequest {
121753f127fSDimitry Andric     COFFSymbolIndex Alias;
122753f127fSDimitry Andric     COFFSymbolIndex Target;
123*972a253aSDimitry Andric     uint32_t Characteristics;
124753f127fSDimitry Andric     StringRef SymbolName;
125753f127fSDimitry Andric   };
126*972a253aSDimitry Andric   std::vector<WeakExternalRequest> WeakExternalRequests;
127753f127fSDimitry Andric 
128753f127fSDimitry Andric   // Per COFF section jitlink symbol set sorted by offset.
129753f127fSDimitry Andric   // Used for calculating implicit size of defined symbols.
130753f127fSDimitry Andric   using SymbolSet = std::set<std::pair<orc::ExecutorAddrDiff, Symbol *>>;
131753f127fSDimitry Andric   std::vector<SymbolSet> SymbolSets;
132753f127fSDimitry Andric 
133753f127fSDimitry Andric   Section &getCommonSection();
134753f127fSDimitry Andric 
135753f127fSDimitry Andric   Expected<Symbol *> createDefinedSymbol(COFFSymbolIndex SymIndex,
136753f127fSDimitry Andric                                          StringRef SymbolName,
137753f127fSDimitry Andric                                          object::COFFSymbolRef Symbol,
138753f127fSDimitry Andric                                          const object::coff_section *Section);
139753f127fSDimitry Andric   Expected<Symbol *> createCOMDATExportRequest(
140753f127fSDimitry Andric       COFFSymbolIndex SymIndex, object::COFFSymbolRef Symbol,
141753f127fSDimitry Andric       const object::coff_aux_section_definition *Definition);
142753f127fSDimitry Andric   Expected<Symbol *> exportCOMDATSymbol(COFFSymbolIndex SymIndex,
143753f127fSDimitry Andric                                         StringRef SymbolName,
144753f127fSDimitry Andric                                         object::COFFSymbolRef Symbol);
145753f127fSDimitry Andric   Error flushWeakAliasRequests();
146753f127fSDimitry Andric   Error calculateImplicitSizeOfSymbols();
147753f127fSDimitry Andric 
148753f127fSDimitry Andric   static uint64_t getSectionAddress(const object::COFFObjectFile &Obj,
149753f127fSDimitry Andric                                     const object::coff_section *Section);
150753f127fSDimitry Andric   static uint64_t getSectionSize(const object::COFFObjectFile &Obj,
151753f127fSDimitry Andric                                  const object::coff_section *Section);
152753f127fSDimitry Andric   static bool isComdatSection(const object::coff_section *Section);
153753f127fSDimitry Andric   static unsigned getPointerSize(const object::COFFObjectFile &Obj);
154753f127fSDimitry Andric   static support::endianness getEndianness(const object::COFFObjectFile &Obj);
155753f127fSDimitry Andric   StringRef getCOFFSectionName(COFFSectionIndex SectionIndex,
156753f127fSDimitry Andric                                const object::coff_section *Sec,
157753f127fSDimitry Andric                                object::COFFSymbolRef Sym);
158753f127fSDimitry Andric 
159753f127fSDimitry Andric   const object::COFFObjectFile &Obj;
160753f127fSDimitry Andric   std::unique_ptr<LinkGraph> G;
161753f127fSDimitry Andric 
162753f127fSDimitry Andric   Section *CommonSection = nullptr;
163753f127fSDimitry Andric   std::vector<Block *> GraphBlocks;
164753f127fSDimitry Andric   std::vector<Symbol *> GraphSymbols;
165*972a253aSDimitry Andric 
166*972a253aSDimitry Andric   DenseMap<StringRef, Symbol *> ExternalSymbols;
167753f127fSDimitry Andric };
168753f127fSDimitry Andric 
169753f127fSDimitry Andric template <typename RelocHandlerFunction>
170753f127fSDimitry Andric Error COFFLinkGraphBuilder::forEachRelocation(const object::SectionRef &RelSec,
171753f127fSDimitry Andric                                               RelocHandlerFunction &&Func,
172753f127fSDimitry Andric                                               bool ProcessDebugSections) {
173753f127fSDimitry Andric 
174753f127fSDimitry Andric   auto COFFRelSect = Obj.getCOFFSection(RelSec);
175753f127fSDimitry Andric 
176753f127fSDimitry Andric   // Target sections have names in valid COFF object files.
177753f127fSDimitry Andric   Expected<StringRef> Name = Obj.getSectionName(COFFRelSect);
178753f127fSDimitry Andric   if (!Name)
179753f127fSDimitry Andric     return Name.takeError();
180753f127fSDimitry Andric   LLVM_DEBUG(dbgs() << "  " << *Name << ":\n");
181753f127fSDimitry Andric 
182753f127fSDimitry Andric   // Lookup the link-graph node corresponding to the target section name.
183753f127fSDimitry Andric   auto *BlockToFix = getGraphBlock(RelSec.getIndex() + 1);
184753f127fSDimitry Andric   if (!BlockToFix)
185753f127fSDimitry Andric     return make_error<StringError>(
186753f127fSDimitry Andric         "Referencing a section that wasn't added to the graph: " + *Name,
187753f127fSDimitry Andric         inconvertibleErrorCode());
188753f127fSDimitry Andric 
189753f127fSDimitry Andric   // Let the callee process relocation entries one by one.
190753f127fSDimitry Andric   for (const auto &R : RelSec.relocations())
191753f127fSDimitry Andric     if (Error Err = Func(R, RelSec, *BlockToFix))
192753f127fSDimitry Andric       return Err;
193753f127fSDimitry Andric 
194753f127fSDimitry Andric   LLVM_DEBUG(dbgs() << "\n");
195753f127fSDimitry Andric   return Error::success();
196753f127fSDimitry Andric }
197753f127fSDimitry Andric 
198753f127fSDimitry Andric } // end namespace jitlink
199753f127fSDimitry Andric } // end namespace llvm
200753f127fSDimitry Andric 
201753f127fSDimitry Andric #endif // LIB_EXECUTIONENGINE_JITLINK_COFFLINKGRAPHBUILDER_H
202