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