156 lines · c
1//===--------- DefineExternalSectionStartAndEndSymbols.h --------*- 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-exception6//7//===----------------------------------------------------------------------===//8//9// Utility class for recognizing external section start and end symbols and10// transforming them into defined symbols for the start and end blocks of the11// associated Section.12//13//===----------------------------------------------------------------------===//14 15#ifndef LLVM_EXECUTIONENGINE_JITLINK_DEFINEEXTERNALSECTIONSTARTANDENDSYMBOLS_H16#define LLVM_EXECUTIONENGINE_JITLINK_DEFINEEXTERNALSECTIONSTARTANDENDSYMBOLS_H17 18#include "llvm/ExecutionEngine/JITLink/JITLink.h"19#include "llvm/Support/Debug.h"20 21#define DEBUG_TYPE "jitlink"22 23namespace llvm {24namespace jitlink {25 26struct SectionRangeSymbolDesc {27 SectionRangeSymbolDesc() = default;28 SectionRangeSymbolDesc(Section &Sec, bool IsStart)29 : Sec(&Sec), IsStart(IsStart) {}30 Section *Sec = nullptr;31 bool IsStart = false;32};33 34/// Pass implementation for the createDefineExternalSectionStartAndEndSymbols35/// function.36template <typename SymbolIdentifierFunction>37class DefineExternalSectionStartAndEndSymbols {38public:39 DefineExternalSectionStartAndEndSymbols(SymbolIdentifierFunction F)40 : F(std::move(F)) {}41 42 Error operator()(LinkGraph &G) {43 44 // This pass will affect the external symbols set, so copy them out into a45 // vector and iterate over that.46 std::vector<Symbol *> Externals(G.external_symbols().begin(),47 G.external_symbols().end());48 49 for (auto *Sym : Externals) {50 SectionRangeSymbolDesc D = F(G, *Sym);51 if (D.Sec) {52 auto &SR = getSectionRange(*D.Sec);53 if (D.IsStart) {54 if (SR.empty())55 G.makeAbsolute(*Sym, orc::ExecutorAddr());56 else57 G.makeDefined(*Sym, *SR.getFirstBlock(), 0, 0, Linkage::Strong,58 Scope::Local, false);59 } else {60 if (SR.empty())61 G.makeAbsolute(*Sym, orc::ExecutorAddr());62 else63 G.makeDefined(*Sym, *SR.getLastBlock(),64 SR.getLastBlock()->getSize(), 0, Linkage::Strong,65 Scope::Local, false);66 }67 }68 }69 return Error::success();70 }71 72private:73 SectionRange &getSectionRange(Section &Sec) {74 return SectionRanges.try_emplace(&Sec, Sec).first->second;75 }76 77 DenseMap<Section *, SectionRange> SectionRanges;78 SymbolIdentifierFunction F;79};80 81/// Returns a JITLink pass (as a function class) that uses the given symbol82/// identification function to identify external section start and end symbols83/// (and their associated Section*s) and transform the identified externals84/// into defined symbols pointing to the start of the first block in the85/// section and the end of the last (start and end symbols for empty sections86/// will be transformed into absolute symbols at address 0).87///88/// The identification function should be callable as89///90/// SectionRangeSymbolDesc (LinkGraph &G, Symbol &Sym)91///92/// If Sym is not a section range start or end symbol then a default93/// constructed SectionRangeSymbolDesc should be returned. If Sym is a start94/// symbol then SectionRangeSymbolDesc(Sec, true), where Sec is a reference to95/// the target Section. If Sym is an end symbol then96/// SectionRangeSymbolDesc(Sec, false) should be returned.97///98/// This pass should be run in the PostAllocationPass pipeline, at which point99/// all blocks should have been assigned their final addresses.100template <typename SymbolIdentifierFunction>101DefineExternalSectionStartAndEndSymbols<SymbolIdentifierFunction>102createDefineExternalSectionStartAndEndSymbolsPass(103 SymbolIdentifierFunction &&F) {104 return DefineExternalSectionStartAndEndSymbols<SymbolIdentifierFunction>(105 std::forward<SymbolIdentifierFunction>(F));106}107 108/// ELF section start/end symbol detection.109inline SectionRangeSymbolDesc110identifyELFSectionStartAndEndSymbols(LinkGraph &G, Symbol &Sym) {111 constexpr StringRef StartSymbolPrefix = "__start_";112 constexpr StringRef EndSymbolPrefix = "__stop_";113 114 auto SymName = Sym.getName();115 if ((*SymName).starts_with(StartSymbolPrefix)) {116 if (auto *Sec = G.findSectionByName(117 (*SymName).drop_front(StartSymbolPrefix.size())))118 return {*Sec, true};119 } else if ((*SymName).starts_with(EndSymbolPrefix)) {120 if (auto *Sec =121 G.findSectionByName((*SymName).drop_front(EndSymbolPrefix.size())))122 return {*Sec, false};123 }124 return {};125}126 127/// MachO section start/end symbol detection.128inline SectionRangeSymbolDesc129identifyMachOSectionStartAndEndSymbols(LinkGraph &G, Symbol &Sym) {130 constexpr StringRef StartSymbolPrefix = "section$start$";131 constexpr StringRef EndSymbolPrefix = "section$end$";132 133 auto SymName = Sym.getName();134 if ((*SymName).starts_with(StartSymbolPrefix)) {135 auto [SegName, SecName] =136 (*SymName).drop_front(StartSymbolPrefix.size()).split('$');137 std::string SectionName = (SegName + "," + SecName).str();138 if (auto *Sec = G.findSectionByName(SectionName))139 return {*Sec, true};140 } else if ((*SymName).starts_with(EndSymbolPrefix)) {141 auto [SegName, SecName] =142 (*SymName).drop_front(EndSymbolPrefix.size()).split('$');143 std::string SectionName = (SegName + "," + SecName).str();144 if (auto *Sec = G.findSectionByName(SectionName))145 return {*Sec, false};146 }147 return {};148}149 150} // end namespace jitlink151} // end namespace llvm152 153#undef DEBUG_TYPE154 155#endif // LLVM_EXECUTIONENGINE_JITLINK_DEFINEEXTERNALSECTIONSTARTANDENDSYMBOLS_H156