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/ExecutionEngine/JITLink/JITLink.h"
18753f127fSDimitry Andric #include "llvm/Object/COFF.h"
19753f127fSDimitry Andric
20bdd1243dSDimitry Andric #include "COFFDirectiveParser.h"
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,
4106c3fb27SDimitry Andric SubtargetFeatures Features,
42753f127fSDimitry Andric LinkGraph::GetEdgeKindNameFunction GetEdgeKindName);
43753f127fSDimitry Andric
getGraph()44753f127fSDimitry Andric LinkGraph &getGraph() const { return *G; }
45753f127fSDimitry Andric
getObject()46753f127fSDimitry Andric const object::COFFObjectFile &getObject() const { return Obj; }
47753f127fSDimitry Andric
48753f127fSDimitry Andric virtual Error addRelocations() = 0;
49753f127fSDimitry Andric
50753f127fSDimitry Andric Error graphifySections();
51753f127fSDimitry Andric Error graphifySymbols();
52753f127fSDimitry Andric
setGraphSymbol(COFFSectionIndex SecIndex,COFFSymbolIndex SymIndex,Symbol & Sym)53753f127fSDimitry Andric void setGraphSymbol(COFFSectionIndex SecIndex, COFFSymbolIndex SymIndex,
54753f127fSDimitry Andric Symbol &Sym) {
55753f127fSDimitry Andric assert(!GraphSymbols[SymIndex] && "Duplicate symbol at index");
56753f127fSDimitry Andric GraphSymbols[SymIndex] = &Sym;
57753f127fSDimitry Andric if (!COFF::isReservedSectionNumber(SecIndex))
58753f127fSDimitry Andric SymbolSets[SecIndex].insert({Sym.getOffset(), &Sym});
59753f127fSDimitry Andric }
60753f127fSDimitry Andric
getGraphSymbol(COFFSymbolIndex SymIndex)61753f127fSDimitry Andric Symbol *getGraphSymbol(COFFSymbolIndex SymIndex) const {
62753f127fSDimitry Andric if (SymIndex < 0 ||
63753f127fSDimitry Andric SymIndex >= static_cast<COFFSymbolIndex>(GraphSymbols.size()))
64753f127fSDimitry Andric return nullptr;
65753f127fSDimitry Andric return GraphSymbols[SymIndex];
66753f127fSDimitry Andric }
67753f127fSDimitry Andric
setGraphBlock(COFFSectionIndex SecIndex,Block * B)68753f127fSDimitry Andric void setGraphBlock(COFFSectionIndex SecIndex, Block *B) {
69753f127fSDimitry Andric assert(!GraphBlocks[SecIndex] && "Duplicate section at index");
70753f127fSDimitry Andric assert(!COFF::isReservedSectionNumber(SecIndex) && "Invalid section index");
71753f127fSDimitry Andric GraphBlocks[SecIndex] = B;
72753f127fSDimitry Andric }
73753f127fSDimitry Andric
getGraphBlock(COFFSectionIndex SecIndex)74753f127fSDimitry Andric Block *getGraphBlock(COFFSectionIndex SecIndex) const {
75753f127fSDimitry Andric if (SecIndex <= 0 ||
76753f127fSDimitry Andric SecIndex >= static_cast<COFFSectionIndex>(GraphSymbols.size()))
77753f127fSDimitry Andric return nullptr;
78753f127fSDimitry Andric return GraphBlocks[SecIndex];
79753f127fSDimitry Andric }
80753f127fSDimitry Andric
sections()81753f127fSDimitry Andric object::COFFObjectFile::section_iterator_range sections() const {
82753f127fSDimitry Andric return Obj.sections();
83753f127fSDimitry Andric }
84753f127fSDimitry Andric
85753f127fSDimitry Andric /// Traverse all matching relocation records in the given section. The handler
86753f127fSDimitry Andric /// function Func should be callable with this signature:
87753f127fSDimitry Andric /// Error(const object::RelocationRef&,
88753f127fSDimitry Andric /// const object::SectionRef&, Section &)
89753f127fSDimitry Andric ///
90753f127fSDimitry Andric template <typename RelocHandlerFunction>
91753f127fSDimitry Andric Error forEachRelocation(const object::SectionRef &RelSec,
92753f127fSDimitry Andric RelocHandlerFunction &&Func,
93753f127fSDimitry Andric bool ProcessDebugSections = false);
94753f127fSDimitry Andric
95753f127fSDimitry Andric /// Traverse all matching relocation records in the given section. Convenience
96753f127fSDimitry Andric /// wrapper to allow passing a member function for the handler.
97753f127fSDimitry Andric ///
98753f127fSDimitry Andric template <typename ClassT, typename RelocHandlerMethod>
99753f127fSDimitry Andric Error forEachRelocation(const object::SectionRef &RelSec, ClassT *Instance,
100753f127fSDimitry Andric RelocHandlerMethod &&Method,
101753f127fSDimitry Andric bool ProcessDebugSections = false) {
102753f127fSDimitry Andric return forEachRelocation(
103753f127fSDimitry Andric RelSec,
104753f127fSDimitry Andric [Instance, Method](const auto &Rel, const auto &Target, auto &GS) {
105753f127fSDimitry Andric return (Instance->*Method)(Rel, Target, GS);
106753f127fSDimitry Andric },
107753f127fSDimitry Andric ProcessDebugSections);
108753f127fSDimitry Andric }
109753f127fSDimitry Andric
110753f127fSDimitry Andric private:
111753f127fSDimitry Andric // Pending comdat symbol export that is initiated by the first symbol of
112753f127fSDimitry Andric // COMDAT sequence.
113753f127fSDimitry Andric struct ComdatExportRequest {
114753f127fSDimitry Andric COFFSymbolIndex SymbolIndex;
115753f127fSDimitry Andric jitlink::Linkage Linkage;
116bdd1243dSDimitry Andric orc::ExecutorAddrDiff Size;
117753f127fSDimitry Andric };
118bdd1243dSDimitry Andric std::vector<std::optional<ComdatExportRequest>> PendingComdatExports;
119753f127fSDimitry Andric
120753f127fSDimitry Andric // This represents a pending request to create a weak external symbol with a
121753f127fSDimitry Andric // name.
122972a253aSDimitry Andric struct WeakExternalRequest {
123753f127fSDimitry Andric COFFSymbolIndex Alias;
124753f127fSDimitry Andric COFFSymbolIndex Target;
125972a253aSDimitry Andric uint32_t Characteristics;
126753f127fSDimitry Andric StringRef SymbolName;
127753f127fSDimitry Andric };
128972a253aSDimitry Andric std::vector<WeakExternalRequest> WeakExternalRequests;
129753f127fSDimitry Andric
130753f127fSDimitry Andric // Per COFF section jitlink symbol set sorted by offset.
131753f127fSDimitry Andric // Used for calculating implicit size of defined symbols.
132753f127fSDimitry Andric using SymbolSet = std::set<std::pair<orc::ExecutorAddrDiff, Symbol *>>;
133753f127fSDimitry Andric std::vector<SymbolSet> SymbolSets;
134753f127fSDimitry Andric
135753f127fSDimitry Andric Section &getCommonSection();
136753f127fSDimitry Andric
137bdd1243dSDimitry Andric Symbol *createExternalSymbol(COFFSymbolIndex SymIndex, StringRef SymbolName,
138bdd1243dSDimitry Andric object::COFFSymbolRef Symbol,
139bdd1243dSDimitry Andric const object::coff_section *Section);
140bdd1243dSDimitry Andric Expected<Symbol *> createAliasSymbol(StringRef SymbolName, Linkage L, Scope S,
141bdd1243dSDimitry Andric Symbol &Target);
142753f127fSDimitry Andric Expected<Symbol *> createDefinedSymbol(COFFSymbolIndex SymIndex,
143753f127fSDimitry Andric StringRef SymbolName,
144753f127fSDimitry Andric object::COFFSymbolRef Symbol,
145753f127fSDimitry Andric const object::coff_section *Section);
146753f127fSDimitry Andric Expected<Symbol *> createCOMDATExportRequest(
147753f127fSDimitry Andric COFFSymbolIndex SymIndex, object::COFFSymbolRef Symbol,
148753f127fSDimitry Andric const object::coff_aux_section_definition *Definition);
149753f127fSDimitry Andric Expected<Symbol *> exportCOMDATSymbol(COFFSymbolIndex SymIndex,
150753f127fSDimitry Andric StringRef SymbolName,
151753f127fSDimitry Andric object::COFFSymbolRef Symbol);
152bdd1243dSDimitry Andric
153bdd1243dSDimitry Andric Error handleDirectiveSection(StringRef Str);
154753f127fSDimitry Andric Error flushWeakAliasRequests();
155bdd1243dSDimitry Andric Error handleAlternateNames();
156753f127fSDimitry Andric Error calculateImplicitSizeOfSymbols();
157753f127fSDimitry Andric
158753f127fSDimitry Andric static uint64_t getSectionAddress(const object::COFFObjectFile &Obj,
159753f127fSDimitry Andric const object::coff_section *Section);
160753f127fSDimitry Andric static uint64_t getSectionSize(const object::COFFObjectFile &Obj,
161753f127fSDimitry Andric const object::coff_section *Section);
162753f127fSDimitry Andric static bool isComdatSection(const object::coff_section *Section);
163753f127fSDimitry Andric static unsigned getPointerSize(const object::COFFObjectFile &Obj);
164*5f757f3fSDimitry Andric static llvm::endianness getEndianness(const object::COFFObjectFile &Obj);
getDLLImportStubPrefix()165bdd1243dSDimitry Andric static StringRef getDLLImportStubPrefix() { return "__imp_"; }
getDirectiveSectionName()166bdd1243dSDimitry Andric static StringRef getDirectiveSectionName() { return ".drectve"; }
167753f127fSDimitry Andric StringRef getCOFFSectionName(COFFSectionIndex SectionIndex,
168753f127fSDimitry Andric const object::coff_section *Sec,
169753f127fSDimitry Andric object::COFFSymbolRef Sym);
170753f127fSDimitry Andric
171753f127fSDimitry Andric const object::COFFObjectFile &Obj;
172753f127fSDimitry Andric std::unique_ptr<LinkGraph> G;
173bdd1243dSDimitry Andric COFFDirectiveParser DirectiveParser;
174753f127fSDimitry Andric
175753f127fSDimitry Andric Section *CommonSection = nullptr;
176753f127fSDimitry Andric std::vector<Block *> GraphBlocks;
177753f127fSDimitry Andric std::vector<Symbol *> GraphSymbols;
178972a253aSDimitry Andric
179bdd1243dSDimitry Andric DenseMap<StringRef, StringRef> AlternateNames;
180972a253aSDimitry Andric DenseMap<StringRef, Symbol *> ExternalSymbols;
181bdd1243dSDimitry Andric DenseMap<StringRef, Symbol *> DefinedSymbols;
182753f127fSDimitry Andric };
183753f127fSDimitry Andric
184753f127fSDimitry Andric template <typename RelocHandlerFunction>
forEachRelocation(const object::SectionRef & RelSec,RelocHandlerFunction && Func,bool ProcessDebugSections)185753f127fSDimitry Andric Error COFFLinkGraphBuilder::forEachRelocation(const object::SectionRef &RelSec,
186753f127fSDimitry Andric RelocHandlerFunction &&Func,
187753f127fSDimitry Andric bool ProcessDebugSections) {
188753f127fSDimitry Andric
189753f127fSDimitry Andric auto COFFRelSect = Obj.getCOFFSection(RelSec);
190753f127fSDimitry Andric
191753f127fSDimitry Andric // Target sections have names in valid COFF object files.
192753f127fSDimitry Andric Expected<StringRef> Name = Obj.getSectionName(COFFRelSect);
193753f127fSDimitry Andric if (!Name)
194753f127fSDimitry Andric return Name.takeError();
19506c3fb27SDimitry Andric
19606c3fb27SDimitry Andric // Skip the unhandled metadata sections.
19706c3fb27SDimitry Andric if (*Name == ".voltbl")
19806c3fb27SDimitry Andric return Error::success();
199753f127fSDimitry Andric LLVM_DEBUG(dbgs() << " " << *Name << ":\n");
200753f127fSDimitry Andric
201753f127fSDimitry Andric // Lookup the link-graph node corresponding to the target section name.
202753f127fSDimitry Andric auto *BlockToFix = getGraphBlock(RelSec.getIndex() + 1);
203753f127fSDimitry Andric if (!BlockToFix)
204753f127fSDimitry Andric return make_error<StringError>(
205753f127fSDimitry Andric "Referencing a section that wasn't added to the graph: " + *Name,
206753f127fSDimitry Andric inconvertibleErrorCode());
207753f127fSDimitry Andric
208753f127fSDimitry Andric // Let the callee process relocation entries one by one.
209753f127fSDimitry Andric for (const auto &R : RelSec.relocations())
210753f127fSDimitry Andric if (Error Err = Func(R, RelSec, *BlockToFix))
211753f127fSDimitry Andric return Err;
212753f127fSDimitry Andric
213753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "\n");
214753f127fSDimitry Andric return Error::success();
215753f127fSDimitry Andric }
216753f127fSDimitry Andric
217753f127fSDimitry Andric } // end namespace jitlink
218753f127fSDimitry Andric } // end namespace llvm
219753f127fSDimitry Andric
220753f127fSDimitry Andric #endif // LIB_EXECUTIONENGINE_JITLINK_COFFLINKGRAPHBUILDER_H
221