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
25using namespace llvm;
26
27MCXCOFFStreamer::MCXCOFFStreamer(MCContext &Context,
28 std::unique_ptr<MCAsmBackend> MAB,
29 std::unique_ptr<MCObjectWriter> OW,
30 std::unique_ptr<MCCodeEmitter> Emitter)
31 : MCObjectStreamer(Context, std::move(MAB), std::move(OW),
32 std::move(Emitter)) {}
33
34XCOFFObjectWriter &MCXCOFFStreamer::getWriter() {
35 return static_cast<XCOFFObjectWriter &>(getAssembler().getWriter());
36}
37
38void MCXCOFFStreamer::changeSection(MCSection *Section, uint32_t Subsection) {
39 MCObjectStreamer::changeSection(Section, Subsection);
40 auto *Sec = static_cast<const MCSectionXCOFF *>(Section);
41 // We might miss calculating the symbols difference as absolute value before
42 // adding fixups when symbol_A without the fragment set is the csect itself
43 // and symbol_B is in it.
44 // TODO: Currently we only set the fragment for XMC_PR csects and DWARF
45 // sections because we don't have other cases that hit this problem yet.
46 // if (IsDwarfSec || CsectProp->MappingClass == XCOFF::XMC_PR)
47 // QualName->setFragment(F);
48 if (Sec->isDwarfSect() || Sec->getMappingClass() == XCOFF::XMC_PR) {
49 MCSymbol *QualNameSymbol = Sec->getQualNameSymbol();
50 // Only set the fragment the first time we're switching to the section.
51 if (!QualNameSymbol->isInSection())
52 QualNameSymbol->setFragment(CurFrag);
53 }
54}
55
56bool MCXCOFFStreamer::emitSymbolAttribute(MCSymbol *Sym,
57 MCSymbolAttr Attribute) {
58 auto *Symbol = static_cast<MCSymbolXCOFF *>(Sym);
59 getAssembler().registerSymbol(Symbol: *Symbol);
60
61 switch (Attribute) {
62 // XCOFF doesn't support the cold feature.
63 case MCSA_Cold:
64 return false;
65
66 case MCSA_Global:
67 case MCSA_Extern:
68 Symbol->setStorageClass(XCOFF::C_EXT);
69 Symbol->setExternal(true);
70 break;
71 case MCSA_LGlobal:
72 Symbol->setStorageClass(XCOFF::C_HIDEXT);
73 Symbol->setExternal(true);
74 break;
75 case llvm::MCSA_Weak:
76 Symbol->setStorageClass(XCOFF::C_WEAKEXT);
77 Symbol->setExternal(true);
78 break;
79 case llvm::MCSA_Hidden:
80 Symbol->setVisibilityType(XCOFF::SYM_V_HIDDEN);
81 break;
82 case llvm::MCSA_Protected:
83 Symbol->setVisibilityType(XCOFF::SYM_V_PROTECTED);
84 break;
85 case llvm::MCSA_Exported:
86 Symbol->setVisibilityType(XCOFF::SYM_V_EXPORTED);
87 break;
88 default:
89 report_fatal_error(reason: "Not implemented yet.");
90 }
91 return true;
92}
93
94void MCXCOFFStreamer::emitXCOFFSymbolLinkageWithVisibility(
95 MCSymbol *Symbol, MCSymbolAttr Linkage, MCSymbolAttr Visibility) {
96
97 emitSymbolAttribute(Sym: Symbol, Attribute: Linkage);
98
99 // When the caller passes `MCSA_Invalid` for the visibility, do not emit one.
100 if (Visibility == MCSA_Invalid)
101 return;
102
103 emitSymbolAttribute(Sym: Symbol, Attribute: Visibility);
104}
105
106void MCXCOFFStreamer::emitXCOFFRefDirective(const MCSymbol *Symbol) {
107 // Add a Fixup here to later record a relocation of type R_REF to prevent the
108 // ref symbol from being garbage collected (by the binder).
109 addFixup(Value: MCSymbolRefExpr::create(Symbol, Ctx&: getContext()),
110 Kind: XCOFF::RelocationType::R_REF);
111}
112
113void MCXCOFFStreamer::emitXCOFFRenameDirective(const MCSymbol *Name,
114 StringRef Rename) {
115 auto *Symbol = static_cast<const MCSymbolXCOFF *>(Name);
116 if (!Symbol->hasRename())
117 report_fatal_error(reason: "Only explicit .rename is supported for XCOFF.");
118}
119
120void MCXCOFFStreamer::emitXCOFFExceptDirective(const MCSymbol *Symbol,
121 const MCSymbol *Trap,
122 unsigned Lang, unsigned Reason,
123 unsigned FunctionSize,
124 bool hasDebug) {
125 getWriter().addExceptionEntry(Symbol, Trap, LanguageCode: Lang, ReasonCode: Reason, FunctionSize,
126 hasDebug);
127}
128
129void MCXCOFFStreamer::emitXCOFFCInfoSym(StringRef Name, StringRef Metadata) {
130 getWriter().addCInfoSymEntry(Name, Metadata);
131}
132
133void MCXCOFFStreamer::emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
134 Align ByteAlignment) {
135 auto &Sym = static_cast<MCSymbolXCOFF &>(*Symbol);
136 getAssembler().registerSymbol(Symbol: *Symbol);
137 Sym.setExternal(Sym.getStorageClass() != XCOFF::C_HIDEXT);
138 Symbol->setCommon(Size, Alignment: ByteAlignment);
139
140 // Default csect align is 4, but common symbols have explicit alignment values
141 // and we should honor it.
142 Sym.getRepresentedCsect()->setAlignment(ByteAlignment);
143
144 // Emit the alignment and storage for the variable to the section.
145 emitValueToAlignment(Alignment: ByteAlignment);
146 emitZeros(NumBytes: Size);
147}
148
149void MCXCOFFStreamer::emitXCOFFLocalCommonSymbol(MCSymbol *LabelSym,
150 uint64_t Size,
151 MCSymbol *CsectSym,
152 Align Alignment) {
153 emitCommonSymbol(Symbol: CsectSym, Size, ByteAlignment: Alignment);
154}
155