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
26using namespace llvm;
27
28MCXCOFFStreamer::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
35bool MCXCOFFStreamer::emitSymbolAttribute(MCSymbol *Sym,
36 MCSymbolAttr Attribute) {
37 auto *Symbol = cast<MCSymbolXCOFF>(Val: Sym);
38 getAssembler().registerSymbol(Symbol: *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(reason: "Not implemented yet.");
69 }
70 return true;
71}
72
73void MCXCOFFStreamer::emitXCOFFSymbolLinkageWithVisibility(
74 MCSymbol *Symbol, MCSymbolAttr Linkage, MCSymbolAttr Visibility) {
75
76 emitSymbolAttribute(Sym: Symbol, Attribute: 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(Sym: Symbol, Attribute: Visibility);
83}
84
85void 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, Ctx&: getContext());
90 std::optional<MCFixupKind> MaybeKind =
91 getAssembler().getBackend().getFixupKind(Name: "R_REF");
92 if (!MaybeKind)
93 report_fatal_error(reason: "failed to get fixup kind for R_REF relocation");
94
95 MCFixupKind Kind = *MaybeKind;
96 MCFixup Fixup = MCFixup::create(Offset: DF->getContents().size(), Value: SRE, Kind);
97 DF->getFixups().push_back(Elt: Fixup);
98}
99
100void MCXCOFFStreamer::emitXCOFFRenameDirective(const MCSymbol *Name,
101 StringRef Rename) {
102 const MCSymbolXCOFF *Symbol = cast<const MCSymbolXCOFF>(Val: Name);
103 if (!Symbol->hasRename())
104 report_fatal_error(reason: "Only explicit .rename is supported for XCOFF.");
105}
106
107void 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(Writer&: getAssembler().getWriter(), Symbol, Trap, LanguageCode: Lang,
115 ReasonCode: Reason, FunctionSize, hasDebug);
116}
117
118void MCXCOFFStreamer::emitXCOFFCInfoSym(StringRef Name, StringRef Metadata) {
119 XCOFF::addCInfoSymEntry(Writer&: getAssembler().getWriter(), Name, Metadata);
120}
121
122void MCXCOFFStreamer::emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
123 Align ByteAlignment) {
124 getAssembler().registerSymbol(Symbol: *Symbol);
125 Symbol->setExternal(cast<MCSymbolXCOFF>(Val: Symbol)->getStorageClass() !=
126 XCOFF::C_HIDEXT);
127 Symbol->setCommon(Size, Alignment: ByteAlignment);
128
129 // Default csect align is 4, but common symbols have explicit alignment values
130 // and we should honor it.
131 cast<MCSymbolXCOFF>(Val: Symbol)->getRepresentedCsect()->setAlignment(
132 ByteAlignment);
133
134 // Emit the alignment and storage for the variable to the section.
135 emitValueToAlignment(Alignment: ByteAlignment);
136 emitZeros(NumBytes: Size);
137}
138
139void MCXCOFFStreamer::emitZerofill(MCSection *Section, MCSymbol *Symbol,
140 uint64_t Size, Align ByteAlignment,
141 SMLoc Loc) {
142 report_fatal_error(reason: "Zero fill not implemented for XCOFF.");
143}
144
145void 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, CB&: Code, Fixups, STI);
151
152 // Add the fixups and data.
153 MCDataFragment *DF = getOrCreateDataFragment(STI: &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(Elt: Fixup);
159 }
160
161 DF->setHasInstructions(STI);
162 DF->getContents().append(in_start: Code.begin(), in_end: Code.end());
163}
164
165void MCXCOFFStreamer::emitXCOFFLocalCommonSymbol(MCSymbol *LabelSym,
166 uint64_t Size,
167 MCSymbol *CsectSym,
168 Align Alignment) {
169 emitCommonSymbol(Symbol: CsectSym, Size, ByteAlignment: Alignment);
170}
171