1249259Sdim//===- lib/MC/AArch64ELFStreamer.cpp - ELF Object Output for AArch64 ------===//
2249259Sdim//
3249259Sdim//                     The LLVM Compiler Infrastructure
4249259Sdim//
5249259Sdim// This file is distributed under the University of Illinois Open Source
6249259Sdim// License. See LICENSE.TXT for details.
7249259Sdim//
8249259Sdim//===----------------------------------------------------------------------===//
9249259Sdim//
10249259Sdim// This file assembles .s files and emits AArch64 ELF .o object files. Different
11249259Sdim// from generic ELF streamer in emitting mapping symbols ($x and $d) to delimit
12249259Sdim// regions of data and code.
13249259Sdim//
14249259Sdim//===----------------------------------------------------------------------===//
15249259Sdim
16249259Sdim#include "llvm/MC/MCELFStreamer.h"
17249259Sdim#include "llvm/ADT/SmallPtrSet.h"
18249259Sdim#include "llvm/ADT/Twine.h"
19249259Sdim#include "llvm/MC/MCAsmBackend.h"
20249259Sdim#include "llvm/MC/MCAssembler.h"
21249259Sdim#include "llvm/MC/MCCodeEmitter.h"
22249259Sdim#include "llvm/MC/MCContext.h"
23249259Sdim#include "llvm/MC/MCELF.h"
24249259Sdim#include "llvm/MC/MCELFStreamer.h"
25249259Sdim#include "llvm/MC/MCELFSymbolFlags.h"
26249259Sdim#include "llvm/MC/MCExpr.h"
27249259Sdim#include "llvm/MC/MCInst.h"
28249259Sdim#include "llvm/MC/MCObjectStreamer.h"
29249259Sdim#include "llvm/MC/MCSection.h"
30249259Sdim#include "llvm/MC/MCSectionELF.h"
31249259Sdim#include "llvm/MC/MCStreamer.h"
32249259Sdim#include "llvm/MC/MCSymbol.h"
33249259Sdim#include "llvm/MC/MCValue.h"
34249259Sdim#include "llvm/Support/Debug.h"
35249259Sdim#include "llvm/Support/ELF.h"
36249259Sdim#include "llvm/Support/ErrorHandling.h"
37249259Sdim#include "llvm/Support/raw_ostream.h"
38249259Sdim
39249259Sdimusing namespace llvm;
40249259Sdim
41249259Sdimnamespace {
42249259Sdim
43249259Sdim/// Extend the generic ELFStreamer class so that it can emit mapping symbols at
44249259Sdim/// the appropriate points in the object files. These symbols are defined in the
45249259Sdim/// AArch64 ELF ABI:
46249259Sdim///    infocenter.arm.com/help/topic/com.arm.doc.ihi0056a/IHI0056A_aaelf64.pdf
47249259Sdim///
48249259Sdim/// In brief: $x or $d should be emitted at the start of each contiguous region
49249259Sdim/// of A64 code or data in a section. In practice, this emission does not rely
50249259Sdim/// on explicit assembler directives but on inherent properties of the
51249259Sdim/// directives doing the emission (e.g. ".byte" is data, "add x0, x0, x0" an
52249259Sdim/// instruction).
53249259Sdim///
54249259Sdim/// As a result this system is orthogonal to the DataRegion infrastructure used
55249259Sdim/// by MachO. Beware!
56249259Sdimclass AArch64ELFStreamer : public MCELFStreamer {
57249259Sdimpublic:
58263509Sdim  AArch64ELFStreamer(MCContext &Context, MCAsmBackend &TAB, raw_ostream &OS,
59263509Sdim                     MCCodeEmitter *Emitter)
60263509Sdim      : MCELFStreamer(Context, 0, TAB, OS, Emitter), MappingSymbolCounter(0),
61263509Sdim        LastEMS(EMS_None) {}
62249259Sdim
63249259Sdim  ~AArch64ELFStreamer() {}
64249259Sdim
65252723Sdim  virtual void ChangeSection(const MCSection *Section,
66252723Sdim                             const MCExpr *Subsection) {
67249259Sdim    // We have to keep track of the mapping symbol state of any sections we
68249259Sdim    // use. Each one should start off as EMS_None, which is provided as the
69249259Sdim    // default constructor by DenseMap::lookup.
70252723Sdim    LastMappingSymbols[getPreviousSection().first] = LastEMS;
71249259Sdim    LastEMS = LastMappingSymbols.lookup(Section);
72249259Sdim
73252723Sdim    MCELFStreamer::ChangeSection(Section, Subsection);
74249259Sdim  }
75249259Sdim
76249259Sdim  /// This function is the one used to emit instruction data into the ELF
77249259Sdim  /// streamer. We override it to add the appropriate mapping symbol if
78249259Sdim  /// necessary.
79249259Sdim  virtual void EmitInstruction(const MCInst& Inst) {
80249259Sdim    EmitA64MappingSymbol();
81249259Sdim    MCELFStreamer::EmitInstruction(Inst);
82249259Sdim  }
83249259Sdim
84249259Sdim  /// This is one of the functions used to emit data into an ELF section, so the
85249259Sdim  /// AArch64 streamer overrides it to add the appropriate mapping symbol ($d)
86249259Sdim  /// if necessary.
87263509Sdim  virtual void EmitBytes(StringRef Data) {
88249259Sdim    EmitDataMappingSymbol();
89263509Sdim    MCELFStreamer::EmitBytes(Data);
90249259Sdim  }
91249259Sdim
92249259Sdim  /// This is one of the functions used to emit data into an ELF section, so the
93249259Sdim  /// AArch64 streamer overrides it to add the appropriate mapping symbol ($d)
94249259Sdim  /// if necessary.
95263509Sdim  virtual void EmitValueImpl(const MCExpr *Value, unsigned Size) {
96249259Sdim    EmitDataMappingSymbol();
97263509Sdim    MCELFStreamer::EmitValueImpl(Value, Size);
98249259Sdim  }
99249259Sdim
100249259Sdimprivate:
101249259Sdim  enum ElfMappingSymbol {
102249259Sdim    EMS_None,
103249259Sdim    EMS_A64,
104249259Sdim    EMS_Data
105249259Sdim  };
106249259Sdim
107249259Sdim  void EmitDataMappingSymbol() {
108249259Sdim    if (LastEMS == EMS_Data) return;
109249259Sdim    EmitMappingSymbol("$d");
110249259Sdim    LastEMS = EMS_Data;
111249259Sdim  }
112249259Sdim
113249259Sdim  void EmitA64MappingSymbol() {
114249259Sdim    if (LastEMS == EMS_A64) return;
115249259Sdim    EmitMappingSymbol("$x");
116249259Sdim    LastEMS = EMS_A64;
117249259Sdim  }
118249259Sdim
119249259Sdim  void EmitMappingSymbol(StringRef Name) {
120249259Sdim    MCSymbol *Start = getContext().CreateTempSymbol();
121249259Sdim    EmitLabel(Start);
122249259Sdim
123249259Sdim    MCSymbol *Symbol =
124249259Sdim      getContext().GetOrCreateSymbol(Name + "." +
125249259Sdim                                     Twine(MappingSymbolCounter++));
126249259Sdim
127249259Sdim    MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol);
128249259Sdim    MCELF::SetType(SD, ELF::STT_NOTYPE);
129249259Sdim    MCELF::SetBinding(SD, ELF::STB_LOCAL);
130249259Sdim    SD.setExternal(false);
131263509Sdim    AssignSection(Symbol, getCurrentSection().first);
132249259Sdim
133249259Sdim    const MCExpr *Value = MCSymbolRefExpr::Create(Start, getContext());
134249259Sdim    Symbol->setVariableValue(Value);
135249259Sdim  }
136249259Sdim
137249259Sdim  int64_t MappingSymbolCounter;
138249259Sdim
139249259Sdim  DenseMap<const MCSection *, ElfMappingSymbol> LastMappingSymbols;
140249259Sdim  ElfMappingSymbol LastEMS;
141249259Sdim
142249259Sdim  /// @}
143249259Sdim};
144249259Sdim}
145249259Sdim
146249259Sdimnamespace llvm {
147249259Sdim  MCELFStreamer* createAArch64ELFStreamer(MCContext &Context, MCAsmBackend &TAB,
148249259Sdim                                      raw_ostream &OS, MCCodeEmitter *Emitter,
149249259Sdim                                      bool RelaxAll, bool NoExecStack) {
150249259Sdim    AArch64ELFStreamer *S = new AArch64ELFStreamer(Context, TAB, OS, Emitter);
151249259Sdim    if (RelaxAll)
152249259Sdim      S->getAssembler().setRelaxAll(true);
153249259Sdim    if (NoExecStack)
154249259Sdim      S->getAssembler().setNoExecStack(true);
155249259Sdim    return S;
156249259Sdim  }
157249259Sdim}
158249259Sdim
159249259Sdim
160