339 lines · cpp
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-exception6//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 21namespace llvm {22namespace orc {23 24void 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 39static Expected<MaterializationUnit::Interface>40getMachOObjectFileSymbolInfo(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 } else63 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 96static Expected<MaterializationUnit::Interface>97getELFObjectFileSymbolInfo(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 } else120 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 150static Expected<MaterializationUnit::Interface>151getCOFFObjectFileSymbolInfo(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 symbols163 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 } else197 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 function209 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 } else226 return SecName.takeError();227 }228 229 return I;230}231 232Expected<MaterializationUnit::Interface>233getXCOFFObjectFileSymbolInfo(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_File245 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 visibility265 // On AIX, symbols with C_EXT and C_WEAKEXT symbols have no specified266 // visibility are considered to have Default scope for LinkGraph. When the267 // object is not a DSO, symbol visibility is not specified. In the absence268 // of an Export List, its reasonable to minimic roughly the behaviour of269 // -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 initializers275 return I;276}277 278Expected<MaterializationUnit::Interface>279getGenericObjectFileSymbolInfo(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 } else302 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 318Expected<MaterializationUnit::Interface>319getObjectFileInterface(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