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