1 //===------ ObjectFileInterface.cpp - MU interface utils for objects ------===// 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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm/ExecutionEngine/Orc/ObjectFileInterface.h" 10 #include "llvm/ExecutionEngine/Orc/COFFPlatform.h" 11 #include "llvm/ExecutionEngine/Orc/ELFNixPlatform.h" 12 #include "llvm/ExecutionEngine/Orc/MachOPlatform.h" 13 #include "llvm/Object/COFF.h" 14 #include "llvm/Object/ELFObjectFile.h" 15 #include "llvm/Object/MachO.h" 16 #include "llvm/Object/ObjectFile.h" 17 #include "llvm/Support/Debug.h" 18 #include <optional> 19 20 #define DEBUG_TYPE "orc" 21 22 namespace llvm { 23 namespace orc { 24 25 void addInitSymbol(MaterializationUnit::Interface &I, ExecutionSession &ES, 26 StringRef ObjFileName) { 27 assert(!I.InitSymbol && "I already has an init symbol"); 28 size_t Counter = 0; 29 30 do { 31 std::string InitSymString; 32 raw_string_ostream(InitSymString) 33 << "$." << ObjFileName << ".__inits." << Counter++; 34 I.InitSymbol = ES.intern(InitSymString); 35 } while (I.SymbolFlags.count(I.InitSymbol)); 36 37 I.SymbolFlags[I.InitSymbol] = JITSymbolFlags::MaterializationSideEffectsOnly; 38 } 39 40 static Expected<MaterializationUnit::Interface> 41 getMachOObjectFileSymbolInfo(ExecutionSession &ES, 42 const object::MachOObjectFile &Obj) { 43 MaterializationUnit::Interface I; 44 45 for (auto &Sym : Obj.symbols()) { 46 Expected<uint32_t> SymFlagsOrErr = Sym.getFlags(); 47 if (!SymFlagsOrErr) 48 // TODO: Test this error. 49 return SymFlagsOrErr.takeError(); 50 51 // Skip symbols not defined in this object file. 52 if (*SymFlagsOrErr & object::BasicSymbolRef::SF_Undefined) 53 continue; 54 55 // Skip symbols that are not global. 56 if (!(*SymFlagsOrErr & object::BasicSymbolRef::SF_Global)) 57 continue; 58 59 // Skip symbols that have type SF_File. 60 if (auto SymType = Sym.getType()) { 61 if (*SymType == object::SymbolRef::ST_File) 62 continue; 63 } else 64 return SymType.takeError(); 65 66 auto Name = Sym.getName(); 67 if (!Name) 68 return Name.takeError(); 69 auto SymFlags = JITSymbolFlags::fromObjectSymbol(Sym); 70 if (!SymFlags) 71 return SymFlags.takeError(); 72 73 // Strip the 'exported' flag from MachO linker-private symbols. 74 if (Name->startswith("l")) 75 *SymFlags &= ~JITSymbolFlags::Exported; 76 77 I.SymbolFlags[ES.intern(*Name)] = std::move(*SymFlags); 78 } 79 80 for (auto &Sec : Obj.sections()) { 81 auto SecType = Obj.getSectionType(Sec); 82 if ((SecType & MachO::SECTION_TYPE) == MachO::S_MOD_INIT_FUNC_POINTERS) { 83 addInitSymbol(I, ES, Obj.getFileName()); 84 break; 85 } 86 auto SegName = Obj.getSectionFinalSegmentName(Sec.getRawDataRefImpl()); 87 auto SecName = cantFail(Obj.getSectionName(Sec.getRawDataRefImpl())); 88 if (MachOPlatform::isInitializerSection(SegName, SecName)) { 89 addInitSymbol(I, ES, Obj.getFileName()); 90 break; 91 } 92 } 93 94 return I; 95 } 96 97 static Expected<MaterializationUnit::Interface> 98 getELFObjectFileSymbolInfo(ExecutionSession &ES, 99 const object::ELFObjectFileBase &Obj) { 100 MaterializationUnit::Interface I; 101 102 for (auto &Sym : Obj.symbols()) { 103 Expected<uint32_t> SymFlagsOrErr = Sym.getFlags(); 104 if (!SymFlagsOrErr) 105 // TODO: Test this error. 106 return SymFlagsOrErr.takeError(); 107 108 // Skip symbols not defined in this object file. 109 if (*SymFlagsOrErr & object::BasicSymbolRef::SF_Undefined) 110 continue; 111 112 // Skip symbols that are not global. 113 if (!(*SymFlagsOrErr & object::BasicSymbolRef::SF_Global)) 114 continue; 115 116 // Skip symbols that have type SF_File. 117 if (auto SymType = Sym.getType()) { 118 if (*SymType == object::SymbolRef::ST_File) 119 continue; 120 } else 121 return SymType.takeError(); 122 123 auto Name = Sym.getName(); 124 if (!Name) 125 return Name.takeError(); 126 127 auto SymFlags = JITSymbolFlags::fromObjectSymbol(Sym); 128 if (!SymFlags) 129 return SymFlags.takeError(); 130 131 // ELF STB_GNU_UNIQUE should map to Weak for ORC. 132 if (Sym.getBinding() == ELF::STB_GNU_UNIQUE) 133 *SymFlags |= JITSymbolFlags::Weak; 134 135 I.SymbolFlags[ES.intern(*Name)] = std::move(*SymFlags); 136 } 137 138 SymbolStringPtr InitSymbol; 139 for (auto &Sec : Obj.sections()) { 140 if (auto SecName = Sec.getName()) { 141 if (ELFNixPlatform::isInitializerSection(*SecName)) { 142 addInitSymbol(I, ES, Obj.getFileName()); 143 break; 144 } 145 } 146 } 147 148 return I; 149 } 150 151 static Expected<MaterializationUnit::Interface> 152 getCOFFObjectFileSymbolInfo(ExecutionSession &ES, 153 const object::COFFObjectFile &Obj) { 154 MaterializationUnit::Interface I; 155 std::vector<std::optional<object::coff_aux_section_definition>> ComdatDefs( 156 Obj.getNumberOfSections() + 1); 157 for (auto &Sym : Obj.symbols()) { 158 Expected<uint32_t> SymFlagsOrErr = Sym.getFlags(); 159 if (!SymFlagsOrErr) 160 // TODO: Test this error. 161 return SymFlagsOrErr.takeError(); 162 163 // Handle comdat symbols 164 auto COFFSym = Obj.getCOFFSymbol(Sym); 165 bool IsWeak = false; 166 if (auto *Def = COFFSym.getSectionDefinition()) { 167 auto Sec = Obj.getSection(COFFSym.getSectionNumber()); 168 if (!Sec) 169 return Sec.takeError(); 170 if (((*Sec)->Characteristics & COFF::IMAGE_SCN_LNK_COMDAT) && 171 Def->Selection != COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) { 172 ComdatDefs[COFFSym.getSectionNumber()] = *Def; 173 continue; 174 } 175 } 176 if (!COFF::isReservedSectionNumber(COFFSym.getSectionNumber()) && 177 ComdatDefs[COFFSym.getSectionNumber()]) { 178 auto Def = ComdatDefs[COFFSym.getSectionNumber()]; 179 if (Def->Selection != COFF::IMAGE_COMDAT_SELECT_NODUPLICATES) { 180 IsWeak = true; 181 } 182 ComdatDefs[COFFSym.getSectionNumber()] = std::nullopt; 183 } else { 184 // Skip symbols not defined in this object file. 185 if (*SymFlagsOrErr & object::BasicSymbolRef::SF_Undefined) 186 continue; 187 } 188 189 // Skip symbols that are not global. 190 if (!(*SymFlagsOrErr & object::BasicSymbolRef::SF_Global)) 191 continue; 192 193 // Skip symbols that have type SF_File. 194 if (auto SymType = Sym.getType()) { 195 if (*SymType == object::SymbolRef::ST_File) 196 continue; 197 } else 198 return SymType.takeError(); 199 200 auto Name = Sym.getName(); 201 if (!Name) 202 return Name.takeError(); 203 204 auto SymFlags = JITSymbolFlags::fromObjectSymbol(Sym); 205 if (!SymFlags) 206 return SymFlags.takeError(); 207 *SymFlags |= JITSymbolFlags::Exported; 208 209 // Weak external is always a function 210 if (COFFSym.isWeakExternal()) 211 *SymFlags |= JITSymbolFlags::Callable; 212 213 if (IsWeak) 214 *SymFlags |= JITSymbolFlags::Weak; 215 216 I.SymbolFlags[ES.intern(*Name)] = std::move(*SymFlags); 217 } 218 219 SymbolStringPtr InitSymbol; 220 for (auto &Sec : Obj.sections()) { 221 if (auto SecName = Sec.getName()) { 222 if (COFFPlatform::isInitializerSection(*SecName)) { 223 addInitSymbol(I, ES, Obj.getFileName()); 224 break; 225 } 226 } else 227 return SecName.takeError(); 228 } 229 230 return I; 231 } 232 233 Expected<MaterializationUnit::Interface> 234 getGenericObjectFileSymbolInfo(ExecutionSession &ES, 235 const object::ObjectFile &Obj) { 236 MaterializationUnit::Interface I; 237 238 for (auto &Sym : Obj.symbols()) { 239 Expected<uint32_t> SymFlagsOrErr = Sym.getFlags(); 240 if (!SymFlagsOrErr) 241 // TODO: Test this error. 242 return SymFlagsOrErr.takeError(); 243 244 // Skip symbols not defined in this object file. 245 if (*SymFlagsOrErr & object::BasicSymbolRef::SF_Undefined) 246 continue; 247 248 // Skip symbols that are not global. 249 if (!(*SymFlagsOrErr & object::BasicSymbolRef::SF_Global)) 250 continue; 251 252 // Skip symbols that have type SF_File. 253 if (auto SymType = Sym.getType()) { 254 if (*SymType == object::SymbolRef::ST_File) 255 continue; 256 } else 257 return SymType.takeError(); 258 259 auto Name = Sym.getName(); 260 if (!Name) 261 return Name.takeError(); 262 263 auto SymFlags = JITSymbolFlags::fromObjectSymbol(Sym); 264 if (!SymFlags) 265 return SymFlags.takeError(); 266 267 I.SymbolFlags[ES.intern(*Name)] = std::move(*SymFlags); 268 } 269 270 return I; 271 } 272 273 Expected<MaterializationUnit::Interface> 274 getObjectFileInterface(ExecutionSession &ES, MemoryBufferRef ObjBuffer) { 275 auto Obj = object::ObjectFile::createObjectFile(ObjBuffer); 276 277 if (!Obj) 278 return Obj.takeError(); 279 280 if (auto *MachOObj = dyn_cast<object::MachOObjectFile>(Obj->get())) 281 return getMachOObjectFileSymbolInfo(ES, *MachOObj); 282 else if (auto *ELFObj = dyn_cast<object::ELFObjectFileBase>(Obj->get())) 283 return getELFObjectFileSymbolInfo(ES, *ELFObj); 284 else if (auto *COFFObj = dyn_cast<object::COFFObjectFile>(Obj->get())) 285 return getCOFFObjectFileSymbolInfo(ES, *COFFObj); 286 287 return getGenericObjectFileSymbolInfo(ES, **Obj); 288 } 289 290 bool hasInitializerSection(jitlink::LinkGraph &G) { 291 bool IsMachO = G.getTargetTriple().isOSBinFormatMachO(); 292 bool IsElf = G.getTargetTriple().isOSBinFormatELF(); 293 if (!IsMachO && !IsElf) 294 return false; 295 296 for (auto &Sec : G.sections()) { 297 if (IsMachO && std::apply(MachOPlatform::isInitializerSection, 298 Sec.getName().split(","))) 299 return true; 300 if (IsElf && ELFNixPlatform::isInitializerSection(Sec.getName())) 301 return true; 302 } 303 304 return false; 305 } 306 307 } // End namespace orc. 308 } // End namespace llvm. 309