1 //===- MCLinkerOptimizationHint.h - LOH interface ---------------*- C++ -*-===// 2 // 3 // 4 // The LLVM Compiler Infrastructure 5 // 6 // This file is distributed under the University of Illinois Open Source 7 // License. See LICENSE.TXT for details. 8 // 9 //===----------------------------------------------------------------------===// 10 // 11 // This file declares some helpers classes to handle Linker Optimization Hint 12 // (LOH). 13 // 14 // FIXME: LOH interface supports only MachO format at the moment. 15 //===----------------------------------------------------------------------===// 16 17 #ifndef LLVM_MC_MCLINKEROPTIMIZATIONHINT_H 18 #define LLVM_MC_MCLINKEROPTIMIZATIONHINT_H 19 20 #include "llvm/ADT/SmallVector.h" 21 #include "llvm/ADT/StringRef.h" 22 #include "llvm/ADT/StringSwitch.h" 23 #include "llvm/MC/MCMachObjectWriter.h" 24 #include "llvm/Support/raw_ostream.h" 25 26 namespace llvm { 27 28 // Forward declarations. 29 class MCAsmLayout; 30 class MCSymbol; 31 32 /// Linker Optimization Hint Type. 33 enum MCLOHType { 34 MCLOH_AdrpAdrp = 0x1u, ///< Adrp xY, _v1@PAGE -> Adrp xY, _v2@PAGE. 35 MCLOH_AdrpLdr = 0x2u, ///< Adrp _v@PAGE -> Ldr _v@PAGEOFF. 36 MCLOH_AdrpAddLdr = 0x3u, ///< Adrp _v@PAGE -> Add _v@PAGEOFF -> Ldr. 37 MCLOH_AdrpLdrGotLdr = 0x4u, ///< Adrp _v@GOTPAGE -> Ldr _v@GOTPAGEOFF -> Ldr. 38 MCLOH_AdrpAddStr = 0x5u, ///< Adrp _v@PAGE -> Add _v@PAGEOFF -> Str. 39 MCLOH_AdrpLdrGotStr = 0x6u, ///< Adrp _v@GOTPAGE -> Ldr _v@GOTPAGEOFF -> Str. 40 MCLOH_AdrpAdd = 0x7u, ///< Adrp _v@PAGE -> Add _v@PAGEOFF. 41 MCLOH_AdrpLdrGot = 0x8u ///< Adrp _v@GOTPAGE -> Ldr _v@GOTPAGEOFF. 42 }; 43 44 static inline StringRef MCLOHDirectiveName() { 45 return StringRef(".loh"); 46 } 47 48 static inline bool isValidMCLOHType(unsigned Kind) { 49 return Kind >= MCLOH_AdrpAdrp && Kind <= MCLOH_AdrpLdrGot; 50 } 51 52 static inline int MCLOHNameToId(StringRef Name) { 53 #define MCLOHCaseNameToId(Name) .Case(#Name, MCLOH_ ## Name) 54 return StringSwitch<int>(Name) 55 MCLOHCaseNameToId(AdrpAdrp) 56 MCLOHCaseNameToId(AdrpLdr) 57 MCLOHCaseNameToId(AdrpAddLdr) 58 MCLOHCaseNameToId(AdrpLdrGotLdr) 59 MCLOHCaseNameToId(AdrpAddStr) 60 MCLOHCaseNameToId(AdrpLdrGotStr) 61 MCLOHCaseNameToId(AdrpAdd) 62 MCLOHCaseNameToId(AdrpLdrGot) 63 .Default(-1); 64 } 65 66 static inline StringRef MCLOHIdToName(MCLOHType Kind) { 67 #define MCLOHCaseIdToName(Name) case MCLOH_ ## Name: return StringRef(#Name); 68 switch (Kind) { 69 MCLOHCaseIdToName(AdrpAdrp); 70 MCLOHCaseIdToName(AdrpLdr); 71 MCLOHCaseIdToName(AdrpAddLdr); 72 MCLOHCaseIdToName(AdrpLdrGotLdr); 73 MCLOHCaseIdToName(AdrpAddStr); 74 MCLOHCaseIdToName(AdrpLdrGotStr); 75 MCLOHCaseIdToName(AdrpAdd); 76 MCLOHCaseIdToName(AdrpLdrGot); 77 } 78 return StringRef(); 79 } 80 81 static inline int MCLOHIdToNbArgs(MCLOHType Kind) { 82 switch (Kind) { 83 // LOH with two arguments 84 case MCLOH_AdrpAdrp: 85 case MCLOH_AdrpLdr: 86 case MCLOH_AdrpAdd: 87 case MCLOH_AdrpLdrGot: 88 return 2; 89 // LOH with three arguments 90 case MCLOH_AdrpAddLdr: 91 case MCLOH_AdrpLdrGotLdr: 92 case MCLOH_AdrpAddStr: 93 case MCLOH_AdrpLdrGotStr: 94 return 3; 95 } 96 return -1; 97 } 98 99 /// Store Linker Optimization Hint information (LOH). 100 class MCLOHDirective { 101 MCLOHType Kind; 102 103 /// Arguments of this directive. Order matters. 104 SmallVector<MCSymbol *, 3> Args; 105 106 /// Emit this directive in \p OutStream using the information available 107 /// in the given \p ObjWriter and \p Layout to get the address of the 108 /// arguments within the object file. 109 void emit_impl(raw_ostream &OutStream, const MachObjectWriter &ObjWriter, 110 const MCAsmLayout &Layout) const; 111 112 public: 113 typedef SmallVectorImpl<MCSymbol *> LOHArgs; 114 115 MCLOHDirective(MCLOHType Kind, const LOHArgs &Args) 116 : Kind(Kind), Args(Args.begin(), Args.end()) { 117 assert(isValidMCLOHType(Kind) && "Invalid LOH directive type!"); 118 } 119 120 MCLOHType getKind() const { return Kind; } 121 122 const LOHArgs &getArgs() const { return Args; } 123 124 /// Emit this directive as: 125 /// <kind, numArgs, addr1, ..., addrN> 126 void emit(MachObjectWriter &ObjWriter, const MCAsmLayout &Layout) const { 127 raw_ostream &OutStream = ObjWriter.getStream(); 128 emit_impl(OutStream, ObjWriter, Layout); 129 } 130 131 /// Get the size in bytes of this directive if emitted in \p ObjWriter with 132 /// the given \p Layout. 133 uint64_t getEmitSize(const MachObjectWriter &ObjWriter, 134 const MCAsmLayout &Layout) const { 135 class raw_counting_ostream : public raw_ostream { 136 uint64_t Count; 137 138 void write_impl(const char *, size_t size) override { Count += size; } 139 140 uint64_t current_pos() const override { return Count; } 141 142 public: 143 raw_counting_ostream() : Count(0) {} 144 ~raw_counting_ostream() override { flush(); } 145 }; 146 147 raw_counting_ostream OutStream; 148 emit_impl(OutStream, ObjWriter, Layout); 149 return OutStream.tell(); 150 } 151 }; 152 153 class MCLOHContainer { 154 /// Keep track of the emit size of all the LOHs. 155 mutable uint64_t EmitSize; 156 157 /// Keep track of all LOH directives. 158 SmallVector<MCLOHDirective, 32> Directives; 159 160 public: 161 typedef SmallVectorImpl<MCLOHDirective> LOHDirectives; 162 163 MCLOHContainer() : EmitSize(0) {} 164 165 /// Const accessor to the directives. 166 const LOHDirectives &getDirectives() const { 167 return Directives; 168 } 169 170 /// Add the directive of the given kind \p Kind with the given arguments 171 /// \p Args to the container. 172 void addDirective(MCLOHType Kind, const MCLOHDirective::LOHArgs &Args) { 173 Directives.push_back(MCLOHDirective(Kind, Args)); 174 } 175 176 /// Get the size of the directives if emitted. 177 uint64_t getEmitSize(const MachObjectWriter &ObjWriter, 178 const MCAsmLayout &Layout) const { 179 if (!EmitSize) { 180 for (const MCLOHDirective &D : Directives) 181 EmitSize += D.getEmitSize(ObjWriter, Layout); 182 } 183 return EmitSize; 184 } 185 186 /// Emit all Linker Optimization Hint in one big table. 187 /// Each line of the table is emitted by LOHDirective::emit. 188 void emit(MachObjectWriter &ObjWriter, const MCAsmLayout &Layout) const { 189 for (const MCLOHDirective &D : Directives) 190 D.emit(ObjWriter, Layout); 191 } 192 193 void reset() { 194 Directives.clear(); 195 EmitSize = 0; 196 } 197 }; 198 199 // Add types for specialized template using MCSymbol. 200 typedef MCLOHDirective::LOHArgs MCLOHArgs; 201 typedef MCLOHContainer::LOHDirectives MCLOHDirectives; 202 203 } // end namespace llvm 204 205 #endif 206