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
getWriter()35 XCOFFObjectWriter &MCXCOFFStreamer::getWriter() {
36 return static_cast<XCOFFObjectWriter &>(getAssembler().getWriter());
37 }
38
emitSymbolAttribute(MCSymbol * Sym,MCSymbolAttr Attribute)39 bool MCXCOFFStreamer::emitSymbolAttribute(MCSymbol *Sym,
40 MCSymbolAttr Attribute) {
41 auto *Symbol = cast<MCSymbolXCOFF>(Sym);
42 getAssembler().registerSymbol(*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("Not implemented yet.");
73 }
74 return true;
75 }
76
emitXCOFFSymbolLinkageWithVisibility(MCSymbol * Symbol,MCSymbolAttr Linkage,MCSymbolAttr Visibility)77 void MCXCOFFStreamer::emitXCOFFSymbolLinkageWithVisibility(
78 MCSymbol *Symbol, MCSymbolAttr Linkage, MCSymbolAttr Visibility) {
79
80 emitSymbolAttribute(Symbol, 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(Symbol, Visibility);
87 }
88
emitXCOFFRefDirective(const MCSymbol * Symbol)89 void 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, getContext());
94 std::optional<MCFixupKind> MaybeKind =
95 getAssembler().getBackend().getFixupKind("R_REF");
96 if (!MaybeKind)
97 report_fatal_error("failed to get fixup kind for R_REF relocation");
98
99 MCFixupKind Kind = *MaybeKind;
100 MCFixup Fixup = MCFixup::create(DF->getContents().size(), SRE, Kind);
101 DF->addFixup(Fixup);
102 }
103
emitXCOFFRenameDirective(const MCSymbol * Name,StringRef Rename)104 void MCXCOFFStreamer::emitXCOFFRenameDirective(const MCSymbol *Name,
105 StringRef Rename) {
106 const MCSymbolXCOFF *Symbol = cast<const MCSymbolXCOFF>(Name);
107 if (!Symbol->hasRename())
108 report_fatal_error("Only explicit .rename is supported for XCOFF.");
109 }
110
emitXCOFFExceptDirective(const MCSymbol * Symbol,const MCSymbol * Trap,unsigned Lang,unsigned Reason,unsigned FunctionSize,bool hasDebug)111 void 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, Lang, Reason, FunctionSize,
117 hasDebug);
118 }
119
emitXCOFFCInfoSym(StringRef Name,StringRef Metadata)120 void MCXCOFFStreamer::emitXCOFFCInfoSym(StringRef Name, StringRef Metadata) {
121 getWriter().addCInfoSymEntry(Name, Metadata);
122 }
123
emitCommonSymbol(MCSymbol * Symbol,uint64_t Size,Align ByteAlignment)124 void MCXCOFFStreamer::emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
125 Align ByteAlignment) {
126 getAssembler().registerSymbol(*Symbol);
127 Symbol->setExternal(cast<MCSymbolXCOFF>(Symbol)->getStorageClass() !=
128 XCOFF::C_HIDEXT);
129 Symbol->setCommon(Size, ByteAlignment);
130
131 // Default csect align is 4, but common symbols have explicit alignment values
132 // and we should honor it.
133 cast<MCSymbolXCOFF>(Symbol)->getRepresentedCsect()->setAlignment(
134 ByteAlignment);
135
136 // Emit the alignment and storage for the variable to the section.
137 emitValueToAlignment(ByteAlignment);
138 emitZeros(Size);
139 }
140
emitXCOFFLocalCommonSymbol(MCSymbol * LabelSym,uint64_t Size,MCSymbol * CsectSym,Align Alignment)141 void MCXCOFFStreamer::emitXCOFFLocalCommonSymbol(MCSymbol *LabelSym,
142 uint64_t Size,
143 MCSymbol *CsectSym,
144 Align Alignment) {
145 emitCommonSymbol(CsectSym, Size, Alignment);
146 }
147