Path: blob/main/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/XCOFFLinkGraphBuilder.cpp
213799 views
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.1// See https://llvm.org/LICENSE.txt for license information.2// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception3//4//===----------------------------------------------------------------------===//5//6// Generic XCOFF LinkGraph building code.7//8//===----------------------------------------------------------------------===//910#include "XCOFFLinkGraphBuilder.h"11#include "llvm/ADT/STLExtras.h"12#include "llvm/BinaryFormat/XCOFF.h"13#include "llvm/ExecutionEngine/JITLink/JITLink.h"14#include "llvm/ExecutionEngine/JITLink/ppc64.h"15#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"16#include "llvm/ExecutionEngine/Orc/Shared/MemoryFlags.h"17#include "llvm/Object/ObjectFile.h"18#include "llvm/Object/XCOFFObjectFile.h"19#include "llvm/Support/Debug.h"20#include "llvm/Support/Error.h"21#include "llvm/Support/Format.h"22#include "llvm/Support/raw_ostream.h"23#include <memory>2425using namespace llvm;2627#define DEBUG_TYPE "jitlink"2829namespace llvm {30namespace jitlink {3132XCOFFLinkGraphBuilder::XCOFFLinkGraphBuilder(33const object::XCOFFObjectFile &Obj,34std::shared_ptr<orc::SymbolStringPool> SSP, Triple TT,35SubtargetFeatures Features,36LinkGraph::GetEdgeKindNameFunction GetEdgeKindName)37: Obj(Obj),38G(std::make_unique<LinkGraph>(39std::string(Obj.getFileName()), std::move(SSP), std::move(TT),40std::move(Features), std::move(GetEdgeKindName))) {}4142#ifndef NDEBUG43static llvm::StringRef getStorageClassString(XCOFF::StorageClass SC) {44switch (SC) {45case XCOFF::StorageClass::C_FILE:46return "C_FILE (File name)";47case XCOFF::StorageClass::C_BINCL:48return "C_BINCL (Beginning of include file)";49case XCOFF::StorageClass::C_EINCL:50return "C_EINCL (Ending of include file)";51case XCOFF::StorageClass::C_GSYM:52return "C_GSYM (Global variable)";53case XCOFF::StorageClass::C_STSYM:54return "C_STSYM (Statically allocated symbol)";55case XCOFF::StorageClass::C_BCOMM:56return "C_BCOMM (Beginning of common block)";57case XCOFF::StorageClass::C_ECOMM:58return "C_ECOMM (End of common block)";59case XCOFF::StorageClass::C_ENTRY:60return "C_ENTRY (Alternate entry)";61case XCOFF::StorageClass::C_BSTAT:62return "C_BSTAT (Beginning of static block)";63case XCOFF::StorageClass::C_ESTAT:64return "C_ESTAT (End of static block)";65case XCOFF::StorageClass::C_GTLS:66return "C_GTLS (Global thread-local variable)";67case XCOFF::StorageClass::C_STTLS:68return "C_STTLS (Static thread-local variable)";69case XCOFF::StorageClass::C_DWARF:70return "C_DWARF (DWARF section symbol)";71case XCOFF::StorageClass::C_LSYM:72return "C_LSYM (Automatic variable allocated on stack)";73case XCOFF::StorageClass::C_PSYM:74return "C_PSYM (Argument to subroutine allocated on stack)";75case XCOFF::StorageClass::C_RSYM:76return "C_RSYM (Register variable)";77case XCOFF::StorageClass::C_RPSYM:78return "C_RPSYM (Argument to function stored in register)";79case XCOFF::StorageClass::C_ECOML:80return "C_ECOML (Local member of common block)";81case XCOFF::StorageClass::C_FUN:82return "C_FUN (Function or procedure)";83case XCOFF::StorageClass::C_EXT:84return "C_EXT (External symbol)";85case XCOFF::StorageClass::C_WEAKEXT:86return "C_WEAKEXT (Weak external symbol)";87case XCOFF::StorageClass::C_NULL:88return "C_NULL";89case XCOFF::StorageClass::C_STAT:90return "C_STAT (Static)";91case XCOFF::StorageClass::C_BLOCK:92return "C_BLOCK (\".bb\" or \".eb\")";93case XCOFF::StorageClass::C_FCN:94return "C_FCN (\".bf\" or \".ef\")";95case XCOFF::StorageClass::C_HIDEXT:96return "C_HIDEXT (Un-named external symbol)";97case XCOFF::StorageClass::C_INFO:98return "C_INFO (Comment string in .info section)";99case XCOFF::StorageClass::C_DECL:100return "C_DECL (Declaration of object)";101case XCOFF::StorageClass::C_AUTO:102return "C_AUTO (Automatic variable)";103case XCOFF::StorageClass::C_REG:104return "C_REG (Register variable)";105case XCOFF::StorageClass::C_EXTDEF:106return "C_EXTDEF (External definition)";107case XCOFF::StorageClass::C_LABEL:108return "C_LABEL (Label)";109case XCOFF::StorageClass::C_ULABEL:110return "C_ULABEL (Undefined label)";111case XCOFF::StorageClass::C_MOS:112return "C_MOS (Member of structure)";113case XCOFF::StorageClass::C_ARG:114return "C_ARG (Function argument)";115case XCOFF::StorageClass::C_STRTAG:116return "C_STRTAG (Structure tag)";117case XCOFF::StorageClass::C_MOU:118return "C_MOU (Member of union)";119case XCOFF::StorageClass::C_UNTAG:120return "C_UNTAG (Union tag)";121case XCOFF::StorageClass::C_TPDEF:122return "C_TPDEF (Type definition)";123case XCOFF::StorageClass::C_USTATIC:124return "C_USTATIC (Undefined static)";125case XCOFF::StorageClass::C_ENTAG:126return "C_ENTAG (Enumeration tag)";127case XCOFF::StorageClass::C_MOE:128return "C_MOE (Member of enumeration)";129case XCOFF::StorageClass::C_REGPARM:130return "C_REGPARM (Register parameter)";131case XCOFF::StorageClass::C_FIELD:132return "C_FIELD (Bit field)";133case XCOFF::StorageClass::C_EOS:134return "C_EOS (End of structure)";135case XCOFF::StorageClass::C_LINE:136return "C_LINE";137case XCOFF::StorageClass::C_ALIAS:138return "C_ALIAS (Duplicate tag)";139case XCOFF::StorageClass::C_HIDDEN:140return "C_HIDDEN (Special storage class for external)";141case XCOFF::StorageClass::C_EFCN:142return "C_EFCN (Physical end of function)";143case XCOFF::StorageClass::C_TCSYM:144return "C_TCSYM (Reserved)";145}146llvm_unreachable("Unknown XCOFF::StorageClass enum");147}148#endif149150Error XCOFFLinkGraphBuilder::processSections() {151LLVM_DEBUG(dbgs() << " Creating graph sections...\n");152153UndefSection = &G->createSection("*UND*", orc::MemProt::None);154155for (object::SectionRef Section : Obj.sections()) {156auto SectionName = Section.getName();157if (!SectionName)158return SectionName.takeError();159160LLVM_DEBUG({161dbgs() << " section = " << *SectionName162<< ", idx = " << Section.getIndex()163<< ", size = " << format_hex_no_prefix(Section.getSize(), 8)164<< ", vma = " << format_hex(Section.getAddress(), 16) << "\n";165});166167// We can skip debug (including dawrf) and pad sections168if (Section.isDebugSection() || *SectionName == "pad")169continue;170LLVM_DEBUG(dbgs() << " creating graph section\n");171172orc::MemProt Prot = orc::MemProt::Read;173if (Section.isText())174Prot |= orc::MemProt::Exec;175if (Section.isData() || Section.isBSS())176Prot |= orc::MemProt::Write;177178jitlink::Section *GraphSec = &G->createSection(*SectionName, Prot);179// TODO: Check for no_alloc for certain sections180181assert(!SectionTable.contains(Section.getIndex()) &&182"Section with same index already exists");183SectionTable[Section.getIndex()] = {GraphSec, Section};184}185186return Error::success();187}188189static std::optional<object::XCOFFSymbolRef>190getXCOFFSymbolContainingSymbolRef(const object::XCOFFObjectFile &Obj,191const object::SymbolRef &Sym) {192const object::XCOFFSymbolRef SymRef =193Obj.toSymbolRef(Sym.getRawDataRefImpl());194if (!SymRef.isCsectSymbol())195return std::nullopt;196197Expected<object::XCOFFCsectAuxRef> CsectAuxEntOrErr =198SymRef.getXCOFFCsectAuxRef();199if (!CsectAuxEntOrErr || !CsectAuxEntOrErr.get().isLabel())200return std::nullopt;201uint32_t Idx =202static_cast<uint32_t>(CsectAuxEntOrErr.get().getSectionOrLength());203object::DataRefImpl DRI;204DRI.p = Obj.getSymbolByIndex(Idx);205return object::XCOFFSymbolRef(DRI, &Obj);206}207208#ifndef NDEBUG209static void printSymbolEntry(raw_ostream &OS,210const object::XCOFFObjectFile &Obj,211const object::XCOFFSymbolRef &Sym) {212OS << " " << format_hex(cantFail(Sym.getAddress()), 16);213OS << " " << left_justify(cantFail(Sym.getName()), 10);214if (Sym.isCsectSymbol()) {215auto CsectAuxEntry = cantFail(Sym.getXCOFFCsectAuxRef());216if (!CsectAuxEntry.isLabel()) {217std::string MCStr =218"[" +219XCOFF::getMappingClassString(CsectAuxEntry.getStorageMappingClass())220.str() +221"]";222OS << left_justify(MCStr, 3);223}224}225OS << " " << format_hex(Sym.getSize(), 8);226OS << " " << Sym.getSectionNumber();227OS << " " << getStorageClassString(Sym.getStorageClass());228OS << " (idx: " << Obj.getSymbolIndex(Sym.getRawDataRefImpl().p) << ")";229if (Sym.isCsectSymbol()) {230if (auto ParentSym = getXCOFFSymbolContainingSymbolRef(Obj, Sym)) {231OS << " (csect idx: "232<< Obj.getSymbolIndex(ParentSym->getRawDataRefImpl().p) << ")";233}234}235OS << "\n";236}237#endif238239Error XCOFFLinkGraphBuilder::processCsectsAndSymbols() {240LLVM_DEBUG(dbgs() << " Creating graph blocks and symbols...\n");241242for ([[maybe_unused]] auto [K, V] : SectionTable) {243LLVM_DEBUG(dbgs() << " section entry(idx: " << K244<< " section: " << V.Section->getName() << ")\n");245}246247for (object::XCOFFSymbolRef Symbol : Obj.symbols()) {248LLVM_DEBUG({ printSymbolEntry(dbgs(), Obj, Symbol); });249250auto Flags = Symbol.getFlags();251if (!Flags)252return Flags.takeError();253254bool External = *Flags & object::SymbolRef::SF_Undefined;255bool Weak = *Flags & object::SymbolRef::SF_Weak;256bool Global = *Flags & object::SymbolRef::SF_Global;257258auto SymbolIndex = Obj.getSymbolIndex(Symbol.getEntryAddress());259auto SymbolName = Symbol.getName();260if (!SymbolName)261return SymbolName.takeError();262263if (External) {264LLVM_DEBUG(dbgs() << " created external symbol\n");265SymbolIndexTable[SymbolIndex] =266&G->addExternalSymbol(*SymbolName, Symbol.getSize(), Weak);267continue;268}269270if (!Symbol.isCsectSymbol()) {271LLVM_DEBUG(dbgs() << " skipped: not a csect symbol\n");272continue;273}274275auto ParentSym = getXCOFFSymbolContainingSymbolRef(Obj, Symbol);276object::XCOFFSymbolRef CsectSymbol = ParentSym ? *ParentSym : Symbol;277278auto CsectSymbolIndex = Obj.getSymbolIndex(CsectSymbol.getEntryAddress());279auto ParentSectionNumber = CsectSymbol.getSectionNumber();280281bool IsUndefinedSection = !SectionTable.contains(ParentSectionNumber);282Section *ParentSection = !IsUndefinedSection283? SectionTable[ParentSectionNumber].Section284: UndefSection;285Block *B = nullptr;286287// TODO: Clean up the logic for handling undefined symbols288if (!CsectTable.contains(CsectSymbolIndex) && !IsUndefinedSection) {289object::SectionRef &SectionRef =290SectionTable[ParentSectionNumber].SectionData;291auto Data = SectionRef.getContents();292if (!Data)293return Data.takeError();294auto CsectSymbolAddr = CsectSymbol.getAddress();295if (!CsectSymbolAddr)296return CsectSymbolAddr.takeError();297298ArrayRef<char> SectionBuffer{*Data};299auto Offset = *CsectSymbolAddr - SectionRef.getAddress();300301LLVM_DEBUG(dbgs() << " symbol entry: offset = " << Offset302<< ", size = " << CsectSymbol.getSize()303<< ", storage class = "304<< getStorageClassString(CsectSymbol.getStorageClass())305<< "\n");306307B = &G->createContentBlock(308*ParentSection, SectionBuffer.slice(Offset, CsectSymbol.getSize()),309orc::ExecutorAddr(*CsectSymbolAddr), CsectSymbol.getAlignment(), 0);310311CsectTable[CsectSymbolIndex] = B;312} else {313B = CsectTable[CsectSymbolIndex];314}315316Scope S{Scope::Local};317if (Symbol.getSymbolType() & XCOFF::SYM_V_HIDDEN ||318Symbol.getSymbolType() & XCOFF::SYM_V_INTERNAL)319S = Scope::Hidden;320else if (Global)321S = Scope::Default;322// TODO: map all symbols for c++ static initialization to SideEffectOnly323324Linkage L = Weak ? Linkage::Weak : Linkage::Strong;325auto SymbolAddr = Symbol.getAddress();326if (!SymbolAddr)327return SymbolAddr.takeError();328auto IsCallableOrErr = Symbol.isFunction();329if (!IsCallableOrErr)330return IsCallableOrErr.takeError();331332auto BlockOffset = *SymbolAddr - B->getAddress().getValue();333334LLVM_DEBUG(dbgs() << " creating with linkage = " << getLinkageName(L)335<< ", scope = " << getScopeName(S) << ", B = "336<< format_hex(B->getAddress().getValue(), 16) << "\n");337338SymbolIndexTable[SymbolIndex] =339&G->addDefinedSymbol(*B, BlockOffset, *SymbolName, Symbol.getSize(), L,340S, *IsCallableOrErr, true);341}342343return Error::success();344}345346Error XCOFFLinkGraphBuilder::processRelocations() {347LLVM_DEBUG(dbgs() << " Creating relocations...\n");348349for (object::SectionRef Section : Obj.sections()) {350auto SectionName = Section.getName();351if (!SectionName)352return SectionName.takeError();353354LLVM_DEBUG(dbgs() << " Relocations for section " << *SectionName355<< ":\n");356357for (object::RelocationRef Relocation : Section.relocations()) {358SmallString<16> RelocName;359Relocation.getTypeName(RelocName);360object::SymbolRef Symbol = *Relocation.getSymbol();361362auto TargetSymbol = Symbol.getName();363if (!TargetSymbol)364return TargetSymbol.takeError();365366auto SymbolIndex = Obj.getSymbolIndex(Symbol.getRawDataRefImpl().p);367368LLVM_DEBUG(dbgs() << " " << format_hex(Relocation.getOffset(), 16)369<< " (idx: " << SymbolIndex << ")"370<< " " << RelocName << " " << *TargetSymbol << "\n";);371372assert(SymbolIndexTable.contains(SymbolIndex) &&373"Relocation needs a record in the symbol table");374auto *S = SymbolIndexTable[SymbolIndex];375auto It = find_if(G->blocks(),376[Target = orc::ExecutorAddr(Section.getAddress() +377Relocation.getOffset())](378const Block *B) -> bool {379return B->getRange().contains(Target);380});381assert(It != G->blocks().end() &&382"Cannot find the target relocation block");383Block *B = *It;384385auto TargetBlockOffset = Section.getAddress() + Relocation.getOffset() -386B->getAddress().getValue();387switch (Relocation.getType()) {388case XCOFF::R_POS:389B->addEdge(ppc64::EdgeKind_ppc64::Pointer64, TargetBlockOffset, *S, 0);390break;391default:392SmallString<16> RelocType;393Relocation.getTypeName(RelocType);394return make_error<StringError>(395"Unsupported Relocation Type: " + RelocType, std::error_code());396}397}398}399400return Error::success();401}402403Expected<std::unique_ptr<LinkGraph>> XCOFFLinkGraphBuilder::buildGraph() {404LLVM_DEBUG(dbgs() << "Building XCOFFLinkGraph...\n");405406// FIXME: Check to make sure the object is relocatable407408if (auto Err = processSections())409return Err;410if (auto Err = processCsectsAndSymbols())411return Err;412if (auto Err = processRelocations())413return Err;414415return std::move(G);416}417418} // namespace jitlink419} // namespace llvm420421422