421 lines · cpp
1// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.2// See https://llvm.org/LICENSE.txt for license information.3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception4//5//===----------------------------------------------------------------------===//6//7// Generic XCOFF LinkGraph building code.8//9//===----------------------------------------------------------------------===//10 11#include "XCOFFLinkGraphBuilder.h"12#include "llvm/ADT/STLExtras.h"13#include "llvm/BinaryFormat/XCOFF.h"14#include "llvm/ExecutionEngine/JITLink/JITLink.h"15#include "llvm/ExecutionEngine/JITLink/ppc64.h"16#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"17#include "llvm/ExecutionEngine/Orc/Shared/MemoryFlags.h"18#include "llvm/Object/ObjectFile.h"19#include "llvm/Object/XCOFFObjectFile.h"20#include "llvm/Support/Debug.h"21#include "llvm/Support/Error.h"22#include "llvm/Support/Format.h"23#include "llvm/Support/raw_ostream.h"24#include <memory>25 26using namespace llvm;27 28#define DEBUG_TYPE "jitlink"29 30namespace llvm {31namespace jitlink {32 33XCOFFLinkGraphBuilder::XCOFFLinkGraphBuilder(34 const object::XCOFFObjectFile &Obj,35 std::shared_ptr<orc::SymbolStringPool> SSP, Triple TT,36 SubtargetFeatures Features,37 LinkGraph::GetEdgeKindNameFunction GetEdgeKindName)38 : Obj(Obj),39 G(std::make_unique<LinkGraph>(40 std::string(Obj.getFileName()), std::move(SSP), std::move(TT),41 std::move(Features), std::move(GetEdgeKindName))) {}42 43#ifndef NDEBUG44static llvm::StringRef getStorageClassString(XCOFF::StorageClass SC) {45 switch (SC) {46 case XCOFF::StorageClass::C_FILE:47 return "C_FILE (File name)";48 case XCOFF::StorageClass::C_BINCL:49 return "C_BINCL (Beginning of include file)";50 case XCOFF::StorageClass::C_EINCL:51 return "C_EINCL (Ending of include file)";52 case XCOFF::StorageClass::C_GSYM:53 return "C_GSYM (Global variable)";54 case XCOFF::StorageClass::C_STSYM:55 return "C_STSYM (Statically allocated symbol)";56 case XCOFF::StorageClass::C_BCOMM:57 return "C_BCOMM (Beginning of common block)";58 case XCOFF::StorageClass::C_ECOMM:59 return "C_ECOMM (End of common block)";60 case XCOFF::StorageClass::C_ENTRY:61 return "C_ENTRY (Alternate entry)";62 case XCOFF::StorageClass::C_BSTAT:63 return "C_BSTAT (Beginning of static block)";64 case XCOFF::StorageClass::C_ESTAT:65 return "C_ESTAT (End of static block)";66 case XCOFF::StorageClass::C_GTLS:67 return "C_GTLS (Global thread-local variable)";68 case XCOFF::StorageClass::C_STTLS:69 return "C_STTLS (Static thread-local variable)";70 case XCOFF::StorageClass::C_DWARF:71 return "C_DWARF (DWARF section symbol)";72 case XCOFF::StorageClass::C_LSYM:73 return "C_LSYM (Automatic variable allocated on stack)";74 case XCOFF::StorageClass::C_PSYM:75 return "C_PSYM (Argument to subroutine allocated on stack)";76 case XCOFF::StorageClass::C_RSYM:77 return "C_RSYM (Register variable)";78 case XCOFF::StorageClass::C_RPSYM:79 return "C_RPSYM (Argument to function stored in register)";80 case XCOFF::StorageClass::C_ECOML:81 return "C_ECOML (Local member of common block)";82 case XCOFF::StorageClass::C_FUN:83 return "C_FUN (Function or procedure)";84 case XCOFF::StorageClass::C_EXT:85 return "C_EXT (External symbol)";86 case XCOFF::StorageClass::C_WEAKEXT:87 return "C_WEAKEXT (Weak external symbol)";88 case XCOFF::StorageClass::C_NULL:89 return "C_NULL";90 case XCOFF::StorageClass::C_STAT:91 return "C_STAT (Static)";92 case XCOFF::StorageClass::C_BLOCK:93 return "C_BLOCK (\".bb\" or \".eb\")";94 case XCOFF::StorageClass::C_FCN:95 return "C_FCN (\".bf\" or \".ef\")";96 case XCOFF::StorageClass::C_HIDEXT:97 return "C_HIDEXT (Un-named external symbol)";98 case XCOFF::StorageClass::C_INFO:99 return "C_INFO (Comment string in .info section)";100 case XCOFF::StorageClass::C_DECL:101 return "C_DECL (Declaration of object)";102 case XCOFF::StorageClass::C_AUTO:103 return "C_AUTO (Automatic variable)";104 case XCOFF::StorageClass::C_REG:105 return "C_REG (Register variable)";106 case XCOFF::StorageClass::C_EXTDEF:107 return "C_EXTDEF (External definition)";108 case XCOFF::StorageClass::C_LABEL:109 return "C_LABEL (Label)";110 case XCOFF::StorageClass::C_ULABEL:111 return "C_ULABEL (Undefined label)";112 case XCOFF::StorageClass::C_MOS:113 return "C_MOS (Member of structure)";114 case XCOFF::StorageClass::C_ARG:115 return "C_ARG (Function argument)";116 case XCOFF::StorageClass::C_STRTAG:117 return "C_STRTAG (Structure tag)";118 case XCOFF::StorageClass::C_MOU:119 return "C_MOU (Member of union)";120 case XCOFF::StorageClass::C_UNTAG:121 return "C_UNTAG (Union tag)";122 case XCOFF::StorageClass::C_TPDEF:123 return "C_TPDEF (Type definition)";124 case XCOFF::StorageClass::C_USTATIC:125 return "C_USTATIC (Undefined static)";126 case XCOFF::StorageClass::C_ENTAG:127 return "C_ENTAG (Enumeration tag)";128 case XCOFF::StorageClass::C_MOE:129 return "C_MOE (Member of enumeration)";130 case XCOFF::StorageClass::C_REGPARM:131 return "C_REGPARM (Register parameter)";132 case XCOFF::StorageClass::C_FIELD:133 return "C_FIELD (Bit field)";134 case XCOFF::StorageClass::C_EOS:135 return "C_EOS (End of structure)";136 case XCOFF::StorageClass::C_LINE:137 return "C_LINE";138 case XCOFF::StorageClass::C_ALIAS:139 return "C_ALIAS (Duplicate tag)";140 case XCOFF::StorageClass::C_HIDDEN:141 return "C_HIDDEN (Special storage class for external)";142 case XCOFF::StorageClass::C_EFCN:143 return "C_EFCN (Physical end of function)";144 case XCOFF::StorageClass::C_TCSYM:145 return "C_TCSYM (Reserved)";146 }147 llvm_unreachable("Unknown XCOFF::StorageClass enum");148}149#endif150 151Error XCOFFLinkGraphBuilder::processSections() {152 LLVM_DEBUG(dbgs() << " Creating graph sections...\n");153 154 UndefSection = &G->createSection("*UND*", orc::MemProt::None);155 156 for (object::SectionRef Section : Obj.sections()) {157 auto SectionName = Section.getName();158 if (!SectionName)159 return SectionName.takeError();160 161 LLVM_DEBUG({162 dbgs() << " section = " << *SectionName163 << ", idx = " << Section.getIndex()164 << ", size = " << format_hex_no_prefix(Section.getSize(), 8)165 << ", vma = " << format_hex(Section.getAddress(), 16) << "\n";166 });167 168 // We can skip debug (including dawrf) and pad sections169 if (Section.isDebugSection() || *SectionName == "pad")170 continue;171 LLVM_DEBUG(dbgs() << " creating graph section\n");172 173 orc::MemProt Prot = orc::MemProt::Read;174 if (Section.isText())175 Prot |= orc::MemProt::Exec;176 if (Section.isData() || Section.isBSS())177 Prot |= orc::MemProt::Write;178 179 jitlink::Section *GraphSec = &G->createSection(*SectionName, Prot);180 // TODO: Check for no_alloc for certain sections181 182 assert(!SectionTable.contains(Section.getIndex()) &&183 "Section with same index already exists");184 SectionTable[Section.getIndex()] = {GraphSec, Section};185 }186 187 return Error::success();188}189 190static std::optional<object::XCOFFSymbolRef>191getXCOFFSymbolContainingSymbolRef(const object::XCOFFObjectFile &Obj,192 const object::SymbolRef &Sym) {193 const object::XCOFFSymbolRef SymRef =194 Obj.toSymbolRef(Sym.getRawDataRefImpl());195 if (!SymRef.isCsectSymbol())196 return std::nullopt;197 198 Expected<object::XCOFFCsectAuxRef> CsectAuxEntOrErr =199 SymRef.getXCOFFCsectAuxRef();200 if (!CsectAuxEntOrErr || !CsectAuxEntOrErr.get().isLabel())201 return std::nullopt;202 uint32_t Idx =203 static_cast<uint32_t>(CsectAuxEntOrErr.get().getSectionOrLength());204 object::DataRefImpl DRI;205 DRI.p = Obj.getSymbolByIndex(Idx);206 return object::XCOFFSymbolRef(DRI, &Obj);207}208 209#ifndef NDEBUG210static void printSymbolEntry(raw_ostream &OS,211 const object::XCOFFObjectFile &Obj,212 const object::XCOFFSymbolRef &Sym) {213 OS << " " << format_hex(cantFail(Sym.getAddress()), 16);214 OS << " " << left_justify(cantFail(Sym.getName()), 10);215 if (Sym.isCsectSymbol()) {216 auto CsectAuxEntry = cantFail(Sym.getXCOFFCsectAuxRef());217 if (!CsectAuxEntry.isLabel()) {218 std::string MCStr =219 "[" +220 XCOFF::getMappingClassString(CsectAuxEntry.getStorageMappingClass())221 .str() +222 "]";223 OS << left_justify(MCStr, 3);224 }225 }226 OS << " " << format_hex(Sym.getSize(), 8);227 OS << " " << Sym.getSectionNumber();228 OS << " " << getStorageClassString(Sym.getStorageClass());229 OS << " (idx: " << Obj.getSymbolIndex(Sym.getRawDataRefImpl().p) << ")";230 if (Sym.isCsectSymbol()) {231 if (auto ParentSym = getXCOFFSymbolContainingSymbolRef(Obj, Sym)) {232 OS << " (csect idx: "233 << Obj.getSymbolIndex(ParentSym->getRawDataRefImpl().p) << ")";234 }235 }236 OS << "\n";237}238#endif239 240Error XCOFFLinkGraphBuilder::processCsectsAndSymbols() {241 LLVM_DEBUG(dbgs() << " Creating graph blocks and symbols...\n");242 243 for ([[maybe_unused]] auto [K, V] : SectionTable) {244 LLVM_DEBUG(dbgs() << " section entry(idx: " << K245 << " section: " << V.Section->getName() << ")\n");246 }247 248 for (object::XCOFFSymbolRef Symbol : Obj.symbols()) {249 LLVM_DEBUG({ printSymbolEntry(dbgs(), Obj, Symbol); });250 251 auto Flags = Symbol.getFlags();252 if (!Flags)253 return Flags.takeError();254 255 bool External = *Flags & object::SymbolRef::SF_Undefined;256 bool Weak = *Flags & object::SymbolRef::SF_Weak;257 bool Global = *Flags & object::SymbolRef::SF_Global;258 259 auto SymbolIndex = Obj.getSymbolIndex(Symbol.getEntryAddress());260 auto SymbolName = Symbol.getName();261 if (!SymbolName)262 return SymbolName.takeError();263 264 if (External) {265 LLVM_DEBUG(dbgs() << " created external symbol\n");266 SymbolIndexTable[SymbolIndex] =267 &G->addExternalSymbol(*SymbolName, Symbol.getSize(), Weak);268 continue;269 }270 271 if (!Symbol.isCsectSymbol()) {272 LLVM_DEBUG(dbgs() << " skipped: not a csect symbol\n");273 continue;274 }275 276 auto ParentSym = getXCOFFSymbolContainingSymbolRef(Obj, Symbol);277 object::XCOFFSymbolRef CsectSymbol = ParentSym ? *ParentSym : Symbol;278 279 auto CsectSymbolIndex = Obj.getSymbolIndex(CsectSymbol.getEntryAddress());280 auto ParentSectionNumber = CsectSymbol.getSectionNumber();281 282 bool IsUndefinedSection = !SectionTable.contains(ParentSectionNumber);283 Section *ParentSection = !IsUndefinedSection284 ? SectionTable[ParentSectionNumber].Section285 : UndefSection;286 Block *B = nullptr;287 288 // TODO: Clean up the logic for handling undefined symbols289 if (!CsectTable.contains(CsectSymbolIndex) && !IsUndefinedSection) {290 object::SectionRef &SectionRef =291 SectionTable[ParentSectionNumber].SectionData;292 auto Data = SectionRef.getContents();293 if (!Data)294 return Data.takeError();295 auto CsectSymbolAddr = CsectSymbol.getAddress();296 if (!CsectSymbolAddr)297 return CsectSymbolAddr.takeError();298 299 ArrayRef<char> SectionBuffer{*Data};300 auto Offset = *CsectSymbolAddr - SectionRef.getAddress();301 302 LLVM_DEBUG(dbgs() << " symbol entry: offset = " << Offset303 << ", size = " << CsectSymbol.getSize()304 << ", storage class = "305 << getStorageClassString(CsectSymbol.getStorageClass())306 << "\n");307 308 B = &G->createContentBlock(309 *ParentSection, SectionBuffer.slice(Offset, CsectSymbol.getSize()),310 orc::ExecutorAddr(*CsectSymbolAddr), CsectSymbol.getAlignment(), 0);311 312 CsectTable[CsectSymbolIndex] = B;313 } else {314 B = CsectTable[CsectSymbolIndex];315 }316 317 Scope S{Scope::Local};318 if (Symbol.getSymbolType() & XCOFF::SYM_V_HIDDEN ||319 Symbol.getSymbolType() & XCOFF::SYM_V_INTERNAL)320 S = Scope::Hidden;321 else if (Global)322 S = Scope::Default;323 // TODO: map all symbols for c++ static initialization to SideEffectOnly324 325 Linkage L = Weak ? Linkage::Weak : Linkage::Strong;326 auto SymbolAddr = Symbol.getAddress();327 if (!SymbolAddr)328 return SymbolAddr.takeError();329 auto IsCallableOrErr = Symbol.isFunction();330 if (!IsCallableOrErr)331 return IsCallableOrErr.takeError();332 333 auto BlockOffset = *SymbolAddr - B->getAddress().getValue();334 335 LLVM_DEBUG(dbgs() << " creating with linkage = " << getLinkageName(L)336 << ", scope = " << getScopeName(S) << ", B = "337 << format_hex(B->getAddress().getValue(), 16) << "\n");338 339 SymbolIndexTable[SymbolIndex] =340 &G->addDefinedSymbol(*B, BlockOffset, *SymbolName, Symbol.getSize(), L,341 S, *IsCallableOrErr, true);342 }343 344 return Error::success();345}346 347Error XCOFFLinkGraphBuilder::processRelocations() {348 LLVM_DEBUG(dbgs() << " Creating relocations...\n");349 350 for (object::SectionRef Section : Obj.sections()) {351 auto SectionName = Section.getName();352 if (!SectionName)353 return SectionName.takeError();354 355 LLVM_DEBUG(dbgs() << " Relocations for section " << *SectionName356 << ":\n");357 358 for (object::RelocationRef Relocation : Section.relocations()) {359 SmallString<16> RelocName;360 Relocation.getTypeName(RelocName);361 object::SymbolRef Symbol = *Relocation.getSymbol();362 363 auto TargetSymbol = Symbol.getName();364 if (!TargetSymbol)365 return TargetSymbol.takeError();366 367 auto SymbolIndex = Obj.getSymbolIndex(Symbol.getRawDataRefImpl().p);368 369 LLVM_DEBUG(dbgs() << " " << format_hex(Relocation.getOffset(), 16)370 << " (idx: " << SymbolIndex << ")"371 << " " << RelocName << " " << *TargetSymbol << "\n";);372 373 assert(SymbolIndexTable.contains(SymbolIndex) &&374 "Relocation needs a record in the symbol table");375 auto *S = SymbolIndexTable[SymbolIndex];376 auto It = find_if(G->blocks(),377 [Target = orc::ExecutorAddr(Section.getAddress() +378 Relocation.getOffset())](379 const Block *B) -> bool {380 return B->getRange().contains(Target);381 });382 assert(It != G->blocks().end() &&383 "Cannot find the target relocation block");384 Block *B = *It;385 386 auto TargetBlockOffset = Section.getAddress() + Relocation.getOffset() -387 B->getAddress().getValue();388 switch (Relocation.getType()) {389 case XCOFF::R_POS:390 B->addEdge(ppc64::EdgeKind_ppc64::Pointer64, TargetBlockOffset, *S, 0);391 break;392 default:393 SmallString<16> RelocType;394 Relocation.getTypeName(RelocType);395 return make_error<StringError>(396 "Unsupported Relocation Type: " + RelocType, std::error_code());397 }398 }399 }400 401 return Error::success();402}403 404Expected<std::unique_ptr<LinkGraph>> XCOFFLinkGraphBuilder::buildGraph() {405 LLVM_DEBUG(dbgs() << "Building XCOFFLinkGraph...\n");406 407 // FIXME: Check to make sure the object is relocatable408 409 if (auto Err = processSections())410 return Err;411 if (auto Err = processCsectsAndSymbols())412 return Err;413 if (auto Err = processRelocations())414 return Err;415 416 return std::move(G);417}418 419} // namespace jitlink420} // namespace llvm421