brintos

brintos / llvm-project-archived public Read only

0
0
Text · 15.0 KiB · f0a14c6 Raw
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