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