1 | //===- MCAssembler.h - Object File Generation -------------------*- C++ -*-===// |
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 | #ifndef LLVM_MC_MCASSEMBLER_H |
10 | #define LLVM_MC_MCASSEMBLER_H |
11 | |
12 | #include "llvm/ADT/ArrayRef.h" |
13 | #include "llvm/ADT/SmallPtrSet.h" |
14 | #include "llvm/ADT/StringRef.h" |
15 | #include "llvm/ADT/iterator.h" |
16 | #include "llvm/ADT/iterator_range.h" |
17 | #include "llvm/BinaryFormat/MachO.h" |
18 | #include "llvm/MC/MCDirectives.h" |
19 | #include "llvm/MC/MCDwarf.h" |
20 | #include "llvm/MC/MCLinkerOptimizationHint.h" |
21 | #include "llvm/MC/MCSymbol.h" |
22 | #include "llvm/Support/SMLoc.h" |
23 | #include "llvm/Support/VersionTuple.h" |
24 | #include <algorithm> |
25 | #include <cassert> |
26 | #include <cstddef> |
27 | #include <cstdint> |
28 | #include <memory> |
29 | #include <string> |
30 | #include <tuple> |
31 | #include <utility> |
32 | #include <vector> |
33 | |
34 | namespace llvm { |
35 | |
36 | class MCBoundaryAlignFragment; |
37 | class MCCVDefRangeFragment; |
38 | class MCCVInlineLineTableFragment; |
39 | class MCDwarfCallFrameFragment; |
40 | class MCDwarfLineAddrFragment; |
41 | class MCEncodedFragment; |
42 | class MCFixup; |
43 | class MCLEBFragment; |
44 | class MCPseudoProbeAddrFragment; |
45 | class MCRelaxableFragment; |
46 | class MCSymbolRefExpr; |
47 | class raw_ostream; |
48 | class MCAsmBackend; |
49 | class MCAsmLayout; |
50 | class MCContext; |
51 | class MCCodeEmitter; |
52 | class MCFragment; |
53 | class MCObjectWriter; |
54 | class MCSection; |
55 | class MCValue; |
56 | |
57 | // FIXME: This really doesn't belong here. See comments below. |
58 | struct IndirectSymbolData { |
59 | MCSymbol *Symbol; |
60 | MCSection *Section; |
61 | }; |
62 | |
63 | // FIXME: Ditto this. Purely so the Streamer and the ObjectWriter can talk |
64 | // to one another. |
65 | struct DataRegionData { |
66 | // This enum should be kept in sync w/ the mach-o definition in |
67 | // llvm/Object/MachOFormat.h. |
68 | enum KindTy { Data = 1, JumpTable8, JumpTable16, JumpTable32 } Kind; |
69 | MCSymbol *Start; |
70 | MCSymbol *End; |
71 | }; |
72 | |
73 | class MCAssembler { |
74 | friend class MCAsmLayout; |
75 | |
76 | public: |
77 | using SectionListType = std::vector<MCSection *>; |
78 | using SymbolDataListType = std::vector<const MCSymbol *>; |
79 | |
80 | using const_iterator = pointee_iterator<SectionListType::const_iterator>; |
81 | using iterator = pointee_iterator<SectionListType::iterator>; |
82 | |
83 | using const_symbol_iterator = |
84 | pointee_iterator<SymbolDataListType::const_iterator>; |
85 | using symbol_iterator = pointee_iterator<SymbolDataListType::iterator>; |
86 | |
87 | using symbol_range = iterator_range<symbol_iterator>; |
88 | using const_symbol_range = iterator_range<const_symbol_iterator>; |
89 | |
90 | using const_indirect_symbol_iterator = |
91 | std::vector<IndirectSymbolData>::const_iterator; |
92 | using indirect_symbol_iterator = std::vector<IndirectSymbolData>::iterator; |
93 | |
94 | using const_data_region_iterator = |
95 | std::vector<DataRegionData>::const_iterator; |
96 | using data_region_iterator = std::vector<DataRegionData>::iterator; |
97 | |
98 | /// MachO specific deployment target version info. |
99 | // A Major version of 0 indicates that no version information was supplied |
100 | // and so the corresponding load command should not be emitted. |
101 | using VersionInfoType = struct { |
102 | bool EmitBuildVersion; |
103 | union { |
104 | MCVersionMinType Type; ///< Used when EmitBuildVersion==false. |
105 | MachO::PlatformType Platform; ///< Used when EmitBuildVersion==true. |
106 | } TypeOrPlatform; |
107 | unsigned Major; |
108 | unsigned Minor; |
109 | unsigned Update; |
110 | /// An optional version of the SDK that was used to build the source. |
111 | VersionTuple SDKVersion; |
112 | }; |
113 | |
114 | private: |
115 | MCContext &Context; |
116 | |
117 | std::unique_ptr<MCAsmBackend> Backend; |
118 | |
119 | std::unique_ptr<MCCodeEmitter> Emitter; |
120 | |
121 | std::unique_ptr<MCObjectWriter> Writer; |
122 | |
123 | SectionListType Sections; |
124 | |
125 | SymbolDataListType Symbols; |
126 | |
127 | std::vector<IndirectSymbolData> IndirectSymbols; |
128 | |
129 | std::vector<DataRegionData> DataRegions; |
130 | |
131 | /// The list of linker options to propagate into the object file. |
132 | std::vector<std::vector<std::string>> LinkerOptions; |
133 | |
134 | /// List of declared file names |
135 | std::vector<std::pair<std::string, size_t>> FileNames; |
136 | // Optional compiler version. |
137 | std::string CompilerVersion; |
138 | |
139 | MCDwarfLineTableParams LTParams; |
140 | |
141 | /// The set of function symbols for which a .thumb_func directive has |
142 | /// been seen. |
143 | // |
144 | // FIXME: We really would like this in target specific code rather than |
145 | // here. Maybe when the relocation stuff moves to target specific, |
146 | // this can go with it? The streamer would need some target specific |
147 | // refactoring too. |
148 | mutable SmallPtrSet<const MCSymbol *, 32> ThumbFuncs; |
149 | |
150 | /// The bundle alignment size currently set in the assembler. |
151 | /// |
152 | /// By default it's 0, which means bundling is disabled. |
153 | unsigned BundleAlignSize; |
154 | |
155 | bool RelaxAll : 1; |
156 | bool SubsectionsViaSymbols : 1; |
157 | bool IncrementalLinkerCompatible : 1; |
158 | |
159 | /// ELF specific e_header flags |
160 | // It would be good if there were an MCELFAssembler class to hold this. |
161 | // ELF header flags are used both by the integrated and standalone assemblers. |
162 | // Access to the flags is necessary in cases where assembler directives affect |
163 | // which flags to be set. |
164 | unsigned ; |
165 | |
166 | /// Used to communicate Linker Optimization Hint information between |
167 | /// the Streamer and the .o writer |
168 | MCLOHContainer LOHContainer; |
169 | |
170 | VersionInfoType VersionInfo; |
171 | VersionInfoType DarwinTargetVariantVersionInfo; |
172 | |
173 | /// Evaluate a fixup to a relocatable expression and the value which should be |
174 | /// placed into the fixup. |
175 | /// |
176 | /// \param Layout The layout to use for evaluation. |
177 | /// \param Fixup The fixup to evaluate. |
178 | /// \param DF The fragment the fixup is inside. |
179 | /// \param Target [out] On return, the relocatable expression the fixup |
180 | /// evaluates to. |
181 | /// \param Value [out] On return, the value of the fixup as currently laid |
182 | /// out. |
183 | /// \param WasForced [out] On return, the value in the fixup is set to the |
184 | /// correct value if WasForced is true, even if evaluateFixup returns false. |
185 | /// \return Whether the fixup value was fully resolved. This is true if the |
186 | /// \p Value result is fixed, otherwise the value may change due to |
187 | /// relocation. |
188 | bool evaluateFixup(const MCAsmLayout &Layout, const MCFixup &Fixup, |
189 | const MCFragment *DF, MCValue &Target, |
190 | const MCSubtargetInfo *STI, uint64_t &Value, |
191 | bool &WasForced) const; |
192 | |
193 | /// Check whether a fixup can be satisfied, or whether it needs to be relaxed |
194 | /// (increased in size, in order to hold its value correctly). |
195 | bool fixupNeedsRelaxation(const MCFixup &Fixup, const MCRelaxableFragment *DF, |
196 | const MCAsmLayout &Layout) const; |
197 | |
198 | /// Check whether the given fragment needs relaxation. |
199 | bool fragmentNeedsRelaxation(const MCRelaxableFragment *IF, |
200 | const MCAsmLayout &Layout) const; |
201 | |
202 | /// Perform one layout iteration and return true if any offsets |
203 | /// were adjusted. |
204 | bool layoutOnce(MCAsmLayout &Layout); |
205 | |
206 | /// Perform one layout iteration of the given section and return true |
207 | /// if any offsets were adjusted. |
208 | bool layoutSectionOnce(MCAsmLayout &Layout, MCSection &Sec); |
209 | |
210 | /// Perform relaxation on a single fragment - returns true if the fragment |
211 | /// changes as a result of relaxation. |
212 | bool relaxFragment(MCAsmLayout &Layout, MCFragment &F); |
213 | bool relaxInstruction(MCAsmLayout &Layout, MCRelaxableFragment &IF); |
214 | bool relaxLEB(MCAsmLayout &Layout, MCLEBFragment &IF); |
215 | bool relaxBoundaryAlign(MCAsmLayout &Layout, MCBoundaryAlignFragment &BF); |
216 | bool relaxDwarfLineAddr(MCAsmLayout &Layout, MCDwarfLineAddrFragment &DF); |
217 | bool relaxDwarfCallFrameFragment(MCAsmLayout &Layout, |
218 | MCDwarfCallFrameFragment &DF); |
219 | bool relaxCVInlineLineTable(MCAsmLayout &Layout, |
220 | MCCVInlineLineTableFragment &DF); |
221 | bool relaxCVDefRange(MCAsmLayout &Layout, MCCVDefRangeFragment &DF); |
222 | bool relaxPseudoProbeAddr(MCAsmLayout &Layout, MCPseudoProbeAddrFragment &DF); |
223 | |
224 | /// finishLayout - Finalize a layout, including fragment lowering. |
225 | void finishLayout(MCAsmLayout &Layout); |
226 | |
227 | std::tuple<MCValue, uint64_t, bool> handleFixup(const MCAsmLayout &Layout, |
228 | MCFragment &F, |
229 | const MCFixup &Fixup, |
230 | const MCSubtargetInfo *STI); |
231 | |
232 | public: |
233 | struct Symver { |
234 | SMLoc Loc; |
235 | const MCSymbol *Sym; |
236 | StringRef Name; |
237 | // True if .symver *, *@@@* or .symver *, *, remove. |
238 | bool KeepOriginalSym; |
239 | }; |
240 | std::vector<Symver> Symvers; |
241 | |
242 | /// Construct a new assembler instance. |
243 | // |
244 | // FIXME: How are we going to parameterize this? Two obvious options are stay |
245 | // concrete and require clients to pass in a target like object. The other |
246 | // option is to make this abstract, and have targets provide concrete |
247 | // implementations as we do with AsmParser. |
248 | MCAssembler(MCContext &Context, std::unique_ptr<MCAsmBackend> Backend, |
249 | std::unique_ptr<MCCodeEmitter> Emitter, |
250 | std::unique_ptr<MCObjectWriter> Writer); |
251 | MCAssembler(const MCAssembler &) = delete; |
252 | MCAssembler &operator=(const MCAssembler &) = delete; |
253 | ~MCAssembler(); |
254 | |
255 | /// Compute the effective fragment size assuming it is laid out at the given |
256 | /// \p SectionAddress and \p FragmentOffset. |
257 | uint64_t computeFragmentSize(const MCAsmLayout &Layout, |
258 | const MCFragment &F) const; |
259 | |
260 | /// Find the symbol which defines the atom containing the given symbol, or |
261 | /// null if there is no such symbol. |
262 | const MCSymbol *getAtom(const MCSymbol &S) const; |
263 | |
264 | /// Check whether a particular symbol is visible to the linker and is required |
265 | /// in the symbol table, or whether it can be discarded by the assembler. This |
266 | /// also effects whether the assembler treats the label as potentially |
267 | /// defining a separate atom. |
268 | bool isSymbolLinkerVisible(const MCSymbol &SD) const; |
269 | |
270 | /// Emit the section contents to \p OS. |
271 | void writeSectionData(raw_ostream &OS, const MCSection *Section, |
272 | const MCAsmLayout &Layout) const; |
273 | |
274 | /// Check whether a given symbol has been flagged with .thumb_func. |
275 | bool isThumbFunc(const MCSymbol *Func) const; |
276 | |
277 | /// Flag a function symbol as the target of a .thumb_func directive. |
278 | void setIsThumbFunc(const MCSymbol *Func) { ThumbFuncs.insert(Ptr: Func); } |
279 | |
280 | /// ELF e_header flags |
281 | unsigned () const { return ELFHeaderEFlags; } |
282 | void (unsigned Flags) { ELFHeaderEFlags = Flags; } |
283 | |
284 | /// MachO deployment target version information. |
285 | const VersionInfoType &getVersionInfo() const { return VersionInfo; } |
286 | void setVersionMin(MCVersionMinType Type, unsigned Major, unsigned Minor, |
287 | unsigned Update, |
288 | VersionTuple SDKVersion = VersionTuple()) { |
289 | VersionInfo.EmitBuildVersion = false; |
290 | VersionInfo.TypeOrPlatform.Type = Type; |
291 | VersionInfo.Major = Major; |
292 | VersionInfo.Minor = Minor; |
293 | VersionInfo.Update = Update; |
294 | VersionInfo.SDKVersion = SDKVersion; |
295 | } |
296 | void setBuildVersion(MachO::PlatformType Platform, unsigned Major, |
297 | unsigned Minor, unsigned Update, |
298 | VersionTuple SDKVersion = VersionTuple()) { |
299 | VersionInfo.EmitBuildVersion = true; |
300 | VersionInfo.TypeOrPlatform.Platform = Platform; |
301 | VersionInfo.Major = Major; |
302 | VersionInfo.Minor = Minor; |
303 | VersionInfo.Update = Update; |
304 | VersionInfo.SDKVersion = SDKVersion; |
305 | } |
306 | |
307 | const VersionInfoType &getDarwinTargetVariantVersionInfo() const { |
308 | return DarwinTargetVariantVersionInfo; |
309 | } |
310 | void setDarwinTargetVariantBuildVersion(MachO::PlatformType Platform, |
311 | unsigned Major, unsigned Minor, |
312 | unsigned Update, |
313 | VersionTuple SDKVersion) { |
314 | DarwinTargetVariantVersionInfo.EmitBuildVersion = true; |
315 | DarwinTargetVariantVersionInfo.TypeOrPlatform.Platform = Platform; |
316 | DarwinTargetVariantVersionInfo.Major = Major; |
317 | DarwinTargetVariantVersionInfo.Minor = Minor; |
318 | DarwinTargetVariantVersionInfo.Update = Update; |
319 | DarwinTargetVariantVersionInfo.SDKVersion = SDKVersion; |
320 | } |
321 | |
322 | /// Reuse an assembler instance |
323 | /// |
324 | void reset(); |
325 | |
326 | MCContext &getContext() const { return Context; } |
327 | |
328 | MCAsmBackend *getBackendPtr() const { return Backend.get(); } |
329 | |
330 | MCCodeEmitter *getEmitterPtr() const { return Emitter.get(); } |
331 | |
332 | MCObjectWriter *getWriterPtr() const { return Writer.get(); } |
333 | |
334 | MCAsmBackend &getBackend() const { return *Backend; } |
335 | |
336 | MCCodeEmitter &getEmitter() const { return *Emitter; } |
337 | |
338 | MCObjectWriter &getWriter() const { return *Writer; } |
339 | |
340 | MCDwarfLineTableParams getDWARFLinetableParams() const { return LTParams; } |
341 | void setDWARFLinetableParams(MCDwarfLineTableParams P) { LTParams = P; } |
342 | |
343 | /// Finish - Do final processing and write the object to the output stream. |
344 | /// \p Writer is used for custom object writer (as the MCJIT does), |
345 | /// if not specified it is automatically created from backend. |
346 | void Finish(); |
347 | |
348 | // Layout all section and prepare them for emission. |
349 | void layout(MCAsmLayout &Layout); |
350 | |
351 | // FIXME: This does not belong here. |
352 | bool getSubsectionsViaSymbols() const { return SubsectionsViaSymbols; } |
353 | void setSubsectionsViaSymbols(bool Value) { SubsectionsViaSymbols = Value; } |
354 | |
355 | bool isIncrementalLinkerCompatible() const { |
356 | return IncrementalLinkerCompatible; |
357 | } |
358 | void setIncrementalLinkerCompatible(bool Value) { |
359 | IncrementalLinkerCompatible = Value; |
360 | } |
361 | |
362 | bool getRelaxAll() const { return RelaxAll; } |
363 | void setRelaxAll(bool Value) { RelaxAll = Value; } |
364 | |
365 | bool isBundlingEnabled() const { return BundleAlignSize != 0; } |
366 | |
367 | unsigned getBundleAlignSize() const { return BundleAlignSize; } |
368 | |
369 | void setBundleAlignSize(unsigned Size) { |
370 | assert((Size == 0 || !(Size & (Size - 1))) && |
371 | "Expect a power-of-two bundle align size" ); |
372 | BundleAlignSize = Size; |
373 | } |
374 | |
375 | /// \name Section List Access |
376 | /// @{ |
377 | |
378 | iterator begin() { return Sections.begin(); } |
379 | const_iterator begin() const { return Sections.begin(); } |
380 | |
381 | iterator end() { return Sections.end(); } |
382 | const_iterator end() const { return Sections.end(); } |
383 | |
384 | size_t size() const { return Sections.size(); } |
385 | |
386 | /// @} |
387 | /// \name Symbol List Access |
388 | /// @{ |
389 | symbol_iterator symbol_begin() { return Symbols.begin(); } |
390 | const_symbol_iterator symbol_begin() const { return Symbols.begin(); } |
391 | |
392 | symbol_iterator symbol_end() { return Symbols.end(); } |
393 | const_symbol_iterator symbol_end() const { return Symbols.end(); } |
394 | |
395 | symbol_range symbols() { return make_range(x: symbol_begin(), y: symbol_end()); } |
396 | const_symbol_range symbols() const { |
397 | return make_range(x: symbol_begin(), y: symbol_end()); |
398 | } |
399 | |
400 | size_t symbol_size() const { return Symbols.size(); } |
401 | |
402 | /// @} |
403 | /// \name Indirect Symbol List Access |
404 | /// @{ |
405 | |
406 | // FIXME: This is a total hack, this should not be here. Once things are |
407 | // factored so that the streamer has direct access to the .o writer, it can |
408 | // disappear. |
409 | std::vector<IndirectSymbolData> &getIndirectSymbols() { |
410 | return IndirectSymbols; |
411 | } |
412 | |
413 | indirect_symbol_iterator indirect_symbol_begin() { |
414 | return IndirectSymbols.begin(); |
415 | } |
416 | const_indirect_symbol_iterator indirect_symbol_begin() const { |
417 | return IndirectSymbols.begin(); |
418 | } |
419 | |
420 | indirect_symbol_iterator indirect_symbol_end() { |
421 | return IndirectSymbols.end(); |
422 | } |
423 | const_indirect_symbol_iterator indirect_symbol_end() const { |
424 | return IndirectSymbols.end(); |
425 | } |
426 | |
427 | size_t indirect_symbol_size() const { return IndirectSymbols.size(); } |
428 | |
429 | /// @} |
430 | /// \name Linker Option List Access |
431 | /// @{ |
432 | |
433 | std::vector<std::vector<std::string>> &getLinkerOptions() { |
434 | return LinkerOptions; |
435 | } |
436 | |
437 | /// @} |
438 | /// \name Data Region List Access |
439 | /// @{ |
440 | |
441 | // FIXME: This is a total hack, this should not be here. Once things are |
442 | // factored so that the streamer has direct access to the .o writer, it can |
443 | // disappear. |
444 | std::vector<DataRegionData> &getDataRegions() { return DataRegions; } |
445 | |
446 | data_region_iterator data_region_begin() { return DataRegions.begin(); } |
447 | const_data_region_iterator data_region_begin() const { |
448 | return DataRegions.begin(); |
449 | } |
450 | |
451 | data_region_iterator data_region_end() { return DataRegions.end(); } |
452 | const_data_region_iterator data_region_end() const { |
453 | return DataRegions.end(); |
454 | } |
455 | |
456 | size_t data_region_size() const { return DataRegions.size(); } |
457 | |
458 | /// @} |
459 | /// \name Data Region List Access |
460 | /// @{ |
461 | |
462 | // FIXME: This is a total hack, this should not be here. Once things are |
463 | // factored so that the streamer has direct access to the .o writer, it can |
464 | // disappear. |
465 | MCLOHContainer &getLOHContainer() { return LOHContainer; } |
466 | const MCLOHContainer &getLOHContainer() const { |
467 | return const_cast<MCAssembler *>(this)->getLOHContainer(); |
468 | } |
469 | |
470 | struct CGProfileEntry { |
471 | const MCSymbolRefExpr *From; |
472 | const MCSymbolRefExpr *To; |
473 | uint64_t Count; |
474 | }; |
475 | std::vector<CGProfileEntry> CGProfile; |
476 | /// @} |
477 | /// \name Backend Data Access |
478 | /// @{ |
479 | |
480 | bool registerSection(MCSection &Section); |
481 | bool registerSymbol(const MCSymbol &Symbol); |
482 | |
483 | MutableArrayRef<std::pair<std::string, size_t>> getFileNames() { |
484 | return FileNames; |
485 | } |
486 | |
487 | void addFileName(StringRef FileName) { |
488 | FileNames.emplace_back(args: std::string(FileName), args: Symbols.size()); |
489 | } |
490 | |
491 | void setCompilerVersion(std::string CompilerVers) { |
492 | if (CompilerVersion.empty()) |
493 | CompilerVersion = std::move(CompilerVers); |
494 | } |
495 | StringRef getCompilerVersion() { return CompilerVersion; } |
496 | |
497 | /// Write the necessary bundle padding to \p OS. |
498 | /// Expects a fragment \p F containing instructions and its size \p FSize. |
499 | void writeFragmentPadding(raw_ostream &OS, const MCEncodedFragment &F, |
500 | uint64_t FSize) const; |
501 | |
502 | /// @} |
503 | |
504 | void dump() const; |
505 | }; |
506 | |
507 | /// Compute the amount of padding required before the fragment \p F to |
508 | /// obey bundling restrictions, where \p FOffset is the fragment's offset in |
509 | /// its section and \p FSize is the fragment's size. |
510 | uint64_t computeBundlePadding(const MCAssembler &Assembler, |
511 | const MCEncodedFragment *F, uint64_t FOffset, |
512 | uint64_t FSize); |
513 | |
514 | } // end namespace llvm |
515 | |
516 | #endif // LLVM_MC_MCASSEMBLER_H |
517 | |