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
MCXCOFFStreamer(MCContext & Context,std::unique_ptr<MCAsmBackend> MAB,std::unique_ptr<MCObjectWriter> OW,std::unique_ptr<MCCodeEmitter> Emitter)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
emitSymbolAttribute(MCSymbol * Sym,MCSymbolAttr Attribute)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
emitXCOFFSymbolLinkageWithVisibility(MCSymbol * Symbol,MCSymbolAttr Linkage,MCSymbolAttr Visibility)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
emitXCOFFRefDirective(const MCSymbol * Symbol)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
emitXCOFFRenameDirective(const MCSymbol * Name,StringRef Rename)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
emitXCOFFExceptDirective(const MCSymbol * Symbol,const MCSymbol * Trap,unsigned Lang,unsigned Reason,unsigned FunctionSize,bool hasDebug)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
emitXCOFFCInfoSym(StringRef Name,StringRef Metadata)118 void MCXCOFFStreamer::emitXCOFFCInfoSym(StringRef Name, StringRef Metadata) {
119 XCOFF::addCInfoSymEntry(getAssembler().getWriter(), Name, Metadata);
120 }
121
emitCommonSymbol(MCSymbol * Symbol,uint64_t Size,Align ByteAlignment)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
emitZerofill(MCSection * Section,MCSymbol * Symbol,uint64_t Size,Align ByteAlignment,SMLoc Loc)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
emitInstToData(const MCInst & Inst,const MCSubtargetInfo & STI)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
emitXCOFFLocalCommonSymbol(MCSymbol * LabelSym,uint64_t Size,MCSymbol * CsectSym,Align Alignment)165 void MCXCOFFStreamer::emitXCOFFLocalCommonSymbol(MCSymbol *LabelSym,
166 uint64_t Size,
167 MCSymbol *CsectSym,
168 Align Alignment) {
169 emitCommonSymbol(CsectSym, Size, Alignment);
170 }
171