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