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
35XCOFFObjectWriter &MCXCOFFStreamer::getWriter() {
36 return static_cast<XCOFFObjectWriter &>(getAssembler().getWriter());
37}
38
39bool MCXCOFFStreamer::emitSymbolAttribute(MCSymbol *Sym,
40 MCSymbolAttr Attribute) {
41 auto *Symbol = cast<MCSymbolXCOFF>(Val: Sym);
42 getAssembler().registerSymbol(Symbol: *Symbol);
43
44 switch (Attribute) {
45 // XCOFF doesn't support the cold feature.
46 case MCSA_Cold:
47 return false;
48
49 case MCSA_Global:
50 case MCSA_Extern:
51 Symbol->setStorageClass(XCOFF::C_EXT);
52 Symbol->setExternal(true);
53 break;
54 case MCSA_LGlobal:
55 Symbol->setStorageClass(XCOFF::C_HIDEXT);
56 Symbol->setExternal(true);
57 break;
58 case llvm::MCSA_Weak:
59 Symbol->setStorageClass(XCOFF::C_WEAKEXT);
60 Symbol->setExternal(true);
61 break;
62 case llvm::MCSA_Hidden:
63 Symbol->setVisibilityType(XCOFF::SYM_V_HIDDEN);
64 break;
65 case llvm::MCSA_Protected:
66 Symbol->setVisibilityType(XCOFF::SYM_V_PROTECTED);
67 break;
68 case llvm::MCSA_Exported:
69 Symbol->setVisibilityType(XCOFF::SYM_V_EXPORTED);
70 break;
71 default:
72 report_fatal_error(reason: "Not implemented yet.");
73 }
74 return true;
75}
76
77void MCXCOFFStreamer::emitXCOFFSymbolLinkageWithVisibility(
78 MCSymbol *Symbol, MCSymbolAttr Linkage, MCSymbolAttr Visibility) {
79
80 emitSymbolAttribute(Sym: Symbol, Attribute: Linkage);
81
82 // When the caller passes `MCSA_Invalid` for the visibility, do not emit one.
83 if (Visibility == MCSA_Invalid)
84 return;
85
86 emitSymbolAttribute(Sym: Symbol, Attribute: Visibility);
87}
88
89void MCXCOFFStreamer::emitXCOFFRefDirective(const MCSymbol *Symbol) {
90 // Add a Fixup here to later record a relocation of type R_REF to prevent the
91 // ref symbol from being garbage collected (by the binder).
92 MCDataFragment *DF = getOrCreateDataFragment();
93 const MCSymbolRefExpr *SRE = MCSymbolRefExpr::create(Symbol, Ctx&: getContext());
94 std::optional<MCFixupKind> MaybeKind =
95 getAssembler().getBackend().getFixupKind(Name: "R_REF");
96 if (!MaybeKind)
97 report_fatal_error(reason: "failed to get fixup kind for R_REF relocation");
98
99 MCFixupKind Kind = *MaybeKind;
100 MCFixup Fixup = MCFixup::create(Offset: DF->getContents().size(), Value: SRE, Kind);
101 DF->addFixup(Fixup);
102}
103
104void MCXCOFFStreamer::emitXCOFFRenameDirective(const MCSymbol *Name,
105 StringRef Rename) {
106 const MCSymbolXCOFF *Symbol = cast<const MCSymbolXCOFF>(Val: Name);
107 if (!Symbol->hasRename())
108 report_fatal_error(reason: "Only explicit .rename is supported for XCOFF.");
109}
110
111void MCXCOFFStreamer::emitXCOFFExceptDirective(const MCSymbol *Symbol,
112 const MCSymbol *Trap,
113 unsigned Lang, unsigned Reason,
114 unsigned FunctionSize,
115 bool hasDebug) {
116 getWriter().addExceptionEntry(Symbol, Trap, LanguageCode: Lang, ReasonCode: Reason, FunctionSize,
117 hasDebug);
118}
119
120void MCXCOFFStreamer::emitXCOFFCInfoSym(StringRef Name, StringRef Metadata) {
121 getWriter().addCInfoSymEntry(Name, Metadata);
122}
123
124void MCXCOFFStreamer::emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
125 Align ByteAlignment) {
126 getAssembler().registerSymbol(Symbol: *Symbol);
127 Symbol->setExternal(cast<MCSymbolXCOFF>(Val: Symbol)->getStorageClass() !=
128 XCOFF::C_HIDEXT);
129 Symbol->setCommon(Size, Alignment: ByteAlignment);
130
131 // Default csect align is 4, but common symbols have explicit alignment values
132 // and we should honor it.
133 cast<MCSymbolXCOFF>(Val: Symbol)->getRepresentedCsect()->setAlignment(
134 ByteAlignment);
135
136 // Emit the alignment and storage for the variable to the section.
137 emitValueToAlignment(Alignment: ByteAlignment);
138 emitZeros(NumBytes: Size);
139}
140
141void MCXCOFFStreamer::emitXCOFFLocalCommonSymbol(MCSymbol *LabelSym,
142 uint64_t Size,
143 MCSymbol *CsectSym,
144 Align Alignment) {
145 emitCommonSymbol(Symbol: CsectSym, Size, ByteAlignment: Alignment);
146}
147