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/TargetRegistry.h" |
23 | #include "llvm/Support/Casting.h" |
24 | |
25 | using namespace llvm; |
26 | |
27 | MCXCOFFStreamer::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 | |
34 | bool MCXCOFFStreamer::emitSymbolAttribute(MCSymbol *Sym, |
35 | MCSymbolAttr Attribute) { |
36 | auto *Symbol = cast<MCSymbolXCOFF>(Val: Sym); |
37 | getAssembler().registerSymbol(Symbol: *Symbol); |
38 | |
39 | switch (Attribute) { |
40 | // XCOFF doesn't support the cold feature. |
41 | case MCSA_Cold: |
42 | return false; |
43 | |
44 | case MCSA_Global: |
45 | case MCSA_Extern: |
46 | Symbol->setStorageClass(XCOFF::C_EXT); |
47 | Symbol->setExternal(true); |
48 | break; |
49 | case MCSA_LGlobal: |
50 | Symbol->setStorageClass(XCOFF::C_HIDEXT); |
51 | Symbol->setExternal(true); |
52 | break; |
53 | case llvm::MCSA_Weak: |
54 | Symbol->setStorageClass(XCOFF::C_WEAKEXT); |
55 | Symbol->setExternal(true); |
56 | break; |
57 | case llvm::MCSA_Hidden: |
58 | Symbol->setVisibilityType(XCOFF::SYM_V_HIDDEN); |
59 | break; |
60 | case llvm::MCSA_Protected: |
61 | Symbol->setVisibilityType(XCOFF::SYM_V_PROTECTED); |
62 | break; |
63 | case llvm::MCSA_Exported: |
64 | Symbol->setVisibilityType(XCOFF::SYM_V_EXPORTED); |
65 | break; |
66 | default: |
67 | report_fatal_error(reason: "Not implemented yet." ); |
68 | } |
69 | return true; |
70 | } |
71 | |
72 | void MCXCOFFStreamer::emitXCOFFSymbolLinkageWithVisibility( |
73 | MCSymbol *Symbol, MCSymbolAttr Linkage, MCSymbolAttr Visibility) { |
74 | |
75 | emitSymbolAttribute(Sym: Symbol, Attribute: Linkage); |
76 | |
77 | // When the caller passes `MCSA_Invalid` for the visibility, do not emit one. |
78 | if (Visibility == MCSA_Invalid) |
79 | return; |
80 | |
81 | emitSymbolAttribute(Sym: Symbol, Attribute: Visibility); |
82 | } |
83 | |
84 | void MCXCOFFStreamer::emitXCOFFRefDirective(const MCSymbol *Symbol) { |
85 | // Add a Fixup here to later record a relocation of type R_REF to prevent the |
86 | // ref symbol from being garbage collected (by the binder). |
87 | MCDataFragment *DF = getOrCreateDataFragment(); |
88 | const MCSymbolRefExpr *SRE = MCSymbolRefExpr::create(Symbol, Ctx&: getContext()); |
89 | std::optional<MCFixupKind> MaybeKind = |
90 | getAssembler().getBackend().getFixupKind(Name: "R_REF" ); |
91 | if (!MaybeKind) |
92 | report_fatal_error(reason: "failed to get fixup kind for R_REF relocation" ); |
93 | |
94 | MCFixupKind Kind = *MaybeKind; |
95 | MCFixup Fixup = MCFixup::create(Offset: DF->getContents().size(), Value: SRE, Kind); |
96 | DF->getFixups().push_back(Elt: Fixup); |
97 | } |
98 | |
99 | void MCXCOFFStreamer::emitXCOFFRenameDirective(const MCSymbol *Name, |
100 | StringRef Rename) { |
101 | const MCSymbolXCOFF *Symbol = cast<const MCSymbolXCOFF>(Val: Name); |
102 | if (!Symbol->hasRename()) |
103 | report_fatal_error(reason: "Only explicit .rename is supported for XCOFF." ); |
104 | } |
105 | |
106 | void MCXCOFFStreamer::emitXCOFFExceptDirective(const MCSymbol *Symbol, |
107 | const MCSymbol *Trap, |
108 | unsigned Lang, unsigned Reason, |
109 | unsigned FunctionSize, |
110 | bool hasDebug) { |
111 | getAssembler().getWriter().addExceptionEntry(Symbol, Trap, LanguageCode: Lang, ReasonCode: Reason, |
112 | FunctionSize, hasDebug); |
113 | } |
114 | |
115 | void MCXCOFFStreamer::emitXCOFFCInfoSym(StringRef Name, StringRef Metadata) { |
116 | getAssembler().getWriter().addCInfoSymEntry(Name, Metadata); |
117 | } |
118 | |
119 | void MCXCOFFStreamer::emitCommonSymbol(MCSymbol *Symbol, uint64_t Size, |
120 | Align ByteAlignment) { |
121 | getAssembler().registerSymbol(Symbol: *Symbol); |
122 | Symbol->setExternal(cast<MCSymbolXCOFF>(Val: Symbol)->getStorageClass() != |
123 | XCOFF::C_HIDEXT); |
124 | Symbol->setCommon(Size, Alignment: ByteAlignment); |
125 | |
126 | // Default csect align is 4, but common symbols have explicit alignment values |
127 | // and we should honor it. |
128 | cast<MCSymbolXCOFF>(Val: Symbol)->getRepresentedCsect()->setAlignment( |
129 | ByteAlignment); |
130 | |
131 | // Emit the alignment and storage for the variable to the section. |
132 | emitValueToAlignment(Alignment: ByteAlignment); |
133 | emitZeros(NumBytes: Size); |
134 | } |
135 | |
136 | void MCXCOFFStreamer::emitZerofill(MCSection *Section, MCSymbol *Symbol, |
137 | uint64_t Size, Align ByteAlignment, |
138 | SMLoc Loc) { |
139 | report_fatal_error(reason: "Zero fill not implemented for XCOFF." ); |
140 | } |
141 | |
142 | void MCXCOFFStreamer::emitInstToData(const MCInst &Inst, |
143 | const MCSubtargetInfo &STI) { |
144 | MCAssembler &Assembler = getAssembler(); |
145 | SmallVector<MCFixup, 4> Fixups; |
146 | SmallString<256> Code; |
147 | Assembler.getEmitter().encodeInstruction(Inst, CB&: Code, Fixups, STI); |
148 | |
149 | // Add the fixups and data. |
150 | MCDataFragment *DF = getOrCreateDataFragment(STI: &STI); |
151 | const size_t ContentsSize = DF->getContents().size(); |
152 | auto &DataFragmentFixups = DF->getFixups(); |
153 | for (auto &Fixup : Fixups) { |
154 | Fixup.setOffset(Fixup.getOffset() + ContentsSize); |
155 | DataFragmentFixups.push_back(Elt: Fixup); |
156 | } |
157 | |
158 | DF->setHasInstructions(STI); |
159 | DF->getContents().append(in_start: Code.begin(), in_end: Code.end()); |
160 | } |
161 | |
162 | MCStreamer *llvm::createXCOFFStreamer(MCContext &Context, |
163 | std::unique_ptr<MCAsmBackend> &&MAB, |
164 | std::unique_ptr<MCObjectWriter> &&OW, |
165 | std::unique_ptr<MCCodeEmitter> &&CE, |
166 | bool RelaxAll) { |
167 | MCXCOFFStreamer *S = new MCXCOFFStreamer(Context, std::move(MAB), |
168 | std::move(OW), std::move(CE)); |
169 | if (RelaxAll) |
170 | S->getAssembler().setRelaxAll(true); |
171 | return S; |
172 | } |
173 | |
174 | void MCXCOFFStreamer::emitXCOFFLocalCommonSymbol(MCSymbol *LabelSym, |
175 | uint64_t Size, |
176 | MCSymbol *CsectSym, |
177 | Align Alignment) { |
178 | emitCommonSymbol(Symbol: CsectSym, Size, ByteAlignment: Alignment); |
179 | } |
180 | |