1 //===- lib/MC/MCXCOFFStreamer.cpp - XCOFF Object Output -------------------===// 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 // This file assembles .s files and emits XCOFF .o object files. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "llvm/MC/MCXCOFFStreamer.h" 14 #include "llvm/BinaryFormat/XCOFF.h" 15 #include "llvm/MC/MCAsmBackend.h" 16 #include "llvm/MC/MCAssembler.h" 17 #include "llvm/MC/MCCodeEmitter.h" 18 #include "llvm/MC/MCDirectives.h" 19 #include "llvm/MC/MCObjectWriter.h" 20 #include "llvm/MC/MCSectionXCOFF.h" 21 #include "llvm/MC/MCSymbolXCOFF.h" 22 #include "llvm/MC/MCXCOFFObjectWriter.h" 23 #include "llvm/MC/TargetRegistry.h" 24 #include "llvm/Support/Casting.h" 25 26 using namespace llvm; 27 28 MCXCOFFStreamer::MCXCOFFStreamer(MCContext &Context, 29 std::unique_ptr<MCAsmBackend> MAB, 30 std::unique_ptr<MCObjectWriter> OW, 31 std::unique_ptr<MCCodeEmitter> Emitter) 32 : MCObjectStreamer(Context, std::move(MAB), std::move(OW), 33 std::move(Emitter)) {} 34 35 bool MCXCOFFStreamer::emitSymbolAttribute(MCSymbol *Sym, 36 MCSymbolAttr Attribute) { 37 auto *Symbol = cast<MCSymbolXCOFF>(Sym); 38 getAssembler().registerSymbol(*Symbol); 39 40 switch (Attribute) { 41 // XCOFF doesn't support the cold feature. 42 case MCSA_Cold: 43 return false; 44 45 case MCSA_Global: 46 case MCSA_Extern: 47 Symbol->setStorageClass(XCOFF::C_EXT); 48 Symbol->setExternal(true); 49 break; 50 case MCSA_LGlobal: 51 Symbol->setStorageClass(XCOFF::C_HIDEXT); 52 Symbol->setExternal(true); 53 break; 54 case llvm::MCSA_Weak: 55 Symbol->setStorageClass(XCOFF::C_WEAKEXT); 56 Symbol->setExternal(true); 57 break; 58 case llvm::MCSA_Hidden: 59 Symbol->setVisibilityType(XCOFF::SYM_V_HIDDEN); 60 break; 61 case llvm::MCSA_Protected: 62 Symbol->setVisibilityType(XCOFF::SYM_V_PROTECTED); 63 break; 64 case llvm::MCSA_Exported: 65 Symbol->setVisibilityType(XCOFF::SYM_V_EXPORTED); 66 break; 67 default: 68 report_fatal_error("Not implemented yet."); 69 } 70 return true; 71 } 72 73 void MCXCOFFStreamer::emitXCOFFSymbolLinkageWithVisibility( 74 MCSymbol *Symbol, MCSymbolAttr Linkage, MCSymbolAttr Visibility) { 75 76 emitSymbolAttribute(Symbol, Linkage); 77 78 // When the caller passes `MCSA_Invalid` for the visibility, do not emit one. 79 if (Visibility == MCSA_Invalid) 80 return; 81 82 emitSymbolAttribute(Symbol, Visibility); 83 } 84 85 void MCXCOFFStreamer::emitXCOFFRefDirective(const MCSymbol *Symbol) { 86 // Add a Fixup here to later record a relocation of type R_REF to prevent the 87 // ref symbol from being garbage collected (by the binder). 88 MCDataFragment *DF = getOrCreateDataFragment(); 89 const MCSymbolRefExpr *SRE = MCSymbolRefExpr::create(Symbol, getContext()); 90 std::optional<MCFixupKind> MaybeKind = 91 getAssembler().getBackend().getFixupKind("R_REF"); 92 if (!MaybeKind) 93 report_fatal_error("failed to get fixup kind for R_REF relocation"); 94 95 MCFixupKind Kind = *MaybeKind; 96 MCFixup Fixup = MCFixup::create(DF->getContents().size(), SRE, Kind); 97 DF->getFixups().push_back(Fixup); 98 } 99 100 void MCXCOFFStreamer::emitXCOFFRenameDirective(const MCSymbol *Name, 101 StringRef Rename) { 102 const MCSymbolXCOFF *Symbol = cast<const MCSymbolXCOFF>(Name); 103 if (!Symbol->hasRename()) 104 report_fatal_error("Only explicit .rename is supported for XCOFF."); 105 } 106 107 void MCXCOFFStreamer::emitXCOFFExceptDirective(const MCSymbol *Symbol, 108 const MCSymbol *Trap, 109 unsigned Lang, unsigned Reason, 110 unsigned FunctionSize, 111 bool hasDebug) { 112 // TODO: Export XCOFFObjectWriter to llvm/MC/MCXCOFFObjectWriter.h and access 113 // it from MCXCOFFStreamer. 114 XCOFF::addExceptionEntry(getAssembler().getWriter(), Symbol, Trap, Lang, 115 Reason, FunctionSize, hasDebug); 116 } 117 118 void MCXCOFFStreamer::emitXCOFFCInfoSym(StringRef Name, StringRef Metadata) { 119 XCOFF::addCInfoSymEntry(getAssembler().getWriter(), Name, Metadata); 120 } 121 122 void MCXCOFFStreamer::emitCommonSymbol(MCSymbol *Symbol, uint64_t Size, 123 Align ByteAlignment) { 124 getAssembler().registerSymbol(*Symbol); 125 Symbol->setExternal(cast<MCSymbolXCOFF>(Symbol)->getStorageClass() != 126 XCOFF::C_HIDEXT); 127 Symbol->setCommon(Size, ByteAlignment); 128 129 // Default csect align is 4, but common symbols have explicit alignment values 130 // and we should honor it. 131 cast<MCSymbolXCOFF>(Symbol)->getRepresentedCsect()->setAlignment( 132 ByteAlignment); 133 134 // Emit the alignment and storage for the variable to the section. 135 emitValueToAlignment(ByteAlignment); 136 emitZeros(Size); 137 } 138 139 void MCXCOFFStreamer::emitZerofill(MCSection *Section, MCSymbol *Symbol, 140 uint64_t Size, Align ByteAlignment, 141 SMLoc Loc) { 142 report_fatal_error("Zero fill not implemented for XCOFF."); 143 } 144 145 void MCXCOFFStreamer::emitInstToData(const MCInst &Inst, 146 const MCSubtargetInfo &STI) { 147 MCAssembler &Assembler = getAssembler(); 148 SmallVector<MCFixup, 4> Fixups; 149 SmallString<256> Code; 150 Assembler.getEmitter().encodeInstruction(Inst, Code, Fixups, STI); 151 152 // Add the fixups and data. 153 MCDataFragment *DF = getOrCreateDataFragment(&STI); 154 const size_t ContentsSize = DF->getContents().size(); 155 auto &DataFragmentFixups = DF->getFixups(); 156 for (auto &Fixup : Fixups) { 157 Fixup.setOffset(Fixup.getOffset() + ContentsSize); 158 DataFragmentFixups.push_back(Fixup); 159 } 160 161 DF->setHasInstructions(STI); 162 DF->getContents().append(Code.begin(), Code.end()); 163 } 164 165 void MCXCOFFStreamer::emitXCOFFLocalCommonSymbol(MCSymbol *LabelSym, 166 uint64_t Size, 167 MCSymbol *CsectSym, 168 Align Alignment) { 169 emitCommonSymbol(CsectSym, Size, Alignment); 170 } 171