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 // XCOFF doesn't support the .weak_definition attribute; reject it like ELF.
67 case MCSA_WeakDefinition:
68 return false;
69
70 case MCSA_Global:
71 case MCSA_Extern:
72 Symbol->setStorageClass(XCOFF::C_EXT);
73 Symbol->setExternal(true);
74 break;
75 case MCSA_LGlobal:
76 Symbol->setStorageClass(XCOFF::C_HIDEXT);
77 Symbol->setExternal(true);
78 break;
79 case llvm::MCSA_Weak:
80 Symbol->setStorageClass(XCOFF::C_WEAKEXT);
81 Symbol->setExternal(true);
82 break;
83 case llvm::MCSA_Hidden:
84 Symbol->setVisibilityType(XCOFF::SYM_V_HIDDEN);
85 break;
86 case llvm::MCSA_Protected:
87 Symbol->setVisibilityType(XCOFF::SYM_V_PROTECTED);
88 break;
89 case llvm::MCSA_Exported:
90 Symbol->setVisibilityType(XCOFF::SYM_V_EXPORTED);
91 break;
92 default:
93 report_fatal_error(reason: "Not implemented yet.");
94 }
95 return true;
96}
97
98void MCXCOFFStreamer::emitXCOFFSymbolLinkageWithVisibility(
99 MCSymbol *Symbol, MCSymbolAttr Linkage, MCSymbolAttr Visibility) {
100
101 emitSymbolAttribute(Sym: Symbol, Attribute: Linkage);
102
103 // When the caller passes `MCSA_Invalid` for the visibility, do not emit one.
104 if (Visibility == MCSA_Invalid)
105 return;
106
107 emitSymbolAttribute(Sym: Symbol, Attribute: Visibility);
108}
109
110void MCXCOFFStreamer::emitXCOFFRefDirective(const MCSymbol *Symbol) {
111 // Add a Fixup here to later record a relocation of type R_REF to prevent the
112 // ref symbol from being garbage collected (by the binder).
113 addFixup(Value: MCSymbolRefExpr::create(Symbol, Ctx&: getContext()),
114 Kind: XCOFF::RelocationType::R_REF);
115}
116
117void MCXCOFFStreamer::emitXCOFFRenameDirective(const MCSymbol *Name,
118 StringRef Rename) {
119 auto *Symbol = static_cast<const MCSymbolXCOFF *>(Name);
120 if (!Symbol->hasRename())
121 report_fatal_error(reason: "Only explicit .rename is supported for XCOFF.");
122}
123
124void MCXCOFFStreamer::emitXCOFFExceptDirective(const MCSymbol *Symbol,
125 const MCSymbol *Trap,
126 unsigned Lang, unsigned Reason,
127 unsigned FunctionSize,
128 bool hasDebug) {
129 getWriter().addExceptionEntry(Symbol, Trap, LanguageCode: Lang, ReasonCode: Reason, FunctionSize,
130 hasDebug);
131}
132
133void MCXCOFFStreamer::emitXCOFFCInfoSym(StringRef Name, StringRef Metadata) {
134 getWriter().addCInfoSymEntry(Name, Metadata);
135}
136
137void MCXCOFFStreamer::emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
138 Align ByteAlignment) {
139 auto &Sym = static_cast<MCSymbolXCOFF &>(*Symbol);
140 getAssembler().registerSymbol(Symbol: *Symbol);
141 Sym.setExternal(Sym.getStorageClass() != XCOFF::C_HIDEXT);
142 Symbol->setCommon(Size, Alignment: ByteAlignment);
143
144 // Default csect align is 4, but common symbols have explicit alignment values
145 // and we should honor it.
146 Sym.getRepresentedCsect()->setAlignment(ByteAlignment);
147
148 // Emit the alignment and storage for the variable to the section.
149 emitValueToAlignment(Alignment: ByteAlignment);
150 emitZeros(NumBytes: Size);
151}
152
153void MCXCOFFStreamer::emitXCOFFLocalCommonSymbol(MCSymbol *LabelSym,
154 uint64_t Size,
155 MCSymbol *CsectSym,
156 Align Alignment) {
157 emitCommonSymbol(Symbol: CsectSym, Size, ByteAlignment: Alignment);
158}
159