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