1 | //===- lib/MC/MCSection.cpp - Machine Code Section Representation ---------===// |
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 | #include "llvm/MC/MCSection.h" |
10 | #include "llvm/ADT/SmallVector.h" |
11 | #include "llvm/Config/llvm-config.h" |
12 | #include "llvm/MC/MCContext.h" |
13 | #include "llvm/MC/MCSymbol.h" |
14 | #include "llvm/Support/Casting.h" |
15 | #include "llvm/Support/Compiler.h" |
16 | #include "llvm/Support/ErrorHandling.h" |
17 | #include "llvm/Support/raw_ostream.h" |
18 | #include <utility> |
19 | |
20 | using namespace llvm; |
21 | |
22 | MCSection::MCSection(SectionVariant V, StringRef Name, bool IsText, |
23 | bool IsVirtual, MCSymbol *Begin) |
24 | : Begin(Begin), BundleGroupBeforeFirstInst(false), HasInstructions(false), |
25 | IsRegistered(false), IsText(IsText), IsVirtual(IsVirtual), |
26 | LinkerRelaxable(false), Name(Name), Variant(V) { |
27 | // The initial subsection number is 0. Create a fragment list. |
28 | CurFragList = &Subsections.emplace_back(Args: 0u, Args: FragList{}).second; |
29 | } |
30 | |
31 | MCSymbol *MCSection::getEndSymbol(MCContext &Ctx) { |
32 | if (!End) |
33 | End = Ctx.createTempSymbol(Name: "sec_end" ); |
34 | return End; |
35 | } |
36 | |
37 | bool MCSection::hasEnded() const { return End && End->isInSection(); } |
38 | |
39 | MCSection::~MCSection() { |
40 | // If ~MCRelaxableFragment becomes trivial (no longer store a MCInst member), |
41 | // this dtor can be made empty. |
42 | for (auto &[_, Chain] : Subsections) { |
43 | for (MCFragment *X = Chain.Head, *Y; X; X = Y) { |
44 | Y = X->Next; |
45 | if (auto *F = dyn_cast<MCRelaxableFragment>(Val: X)) |
46 | F->~MCRelaxableFragment(); |
47 | } |
48 | } |
49 | } |
50 | |
51 | void MCSection::setBundleLockState(BundleLockStateType NewState) { |
52 | if (NewState == NotBundleLocked) { |
53 | if (BundleLockNestingDepth == 0) { |
54 | report_fatal_error(reason: "Mismatched bundle_lock/unlock directives" ); |
55 | } |
56 | if (--BundleLockNestingDepth == 0) { |
57 | BundleLockState = NotBundleLocked; |
58 | } |
59 | return; |
60 | } |
61 | |
62 | // If any of the directives is an align_to_end directive, the whole nested |
63 | // group is align_to_end. So don't downgrade from align_to_end to just locked. |
64 | if (BundleLockState != BundleLockedAlignToEnd) { |
65 | BundleLockState = NewState; |
66 | } |
67 | ++BundleLockNestingDepth; |
68 | } |
69 | |
70 | StringRef MCSection::getVirtualSectionKind() const { return "virtual" ; } |
71 | |
72 | #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) |
73 | LLVM_DUMP_METHOD void MCSection::dump( |
74 | DenseMap<const MCFragment *, SmallVector<const MCSymbol *, 0>> *FragToSyms) |
75 | const { |
76 | raw_ostream &OS = errs(); |
77 | |
78 | OS << "MCSection Name:" << getName(); |
79 | for (auto &F : *this) { |
80 | OS << '\n'; |
81 | F.dump(); |
82 | if (!FragToSyms) |
83 | continue; |
84 | auto It = FragToSyms->find(&F); |
85 | if (It == FragToSyms->end()) |
86 | continue; |
87 | for (auto *Sym : It->second) { |
88 | OS << "\n Symbol @" << Sym->getOffset() << ' ' << Sym->getName(); |
89 | if (Sym->isTemporary()) |
90 | OS << " Temporary" ; |
91 | } |
92 | } |
93 | } |
94 | #endif |
95 | |
96 | void MCEncodedFragment::setContents(ArrayRef<char> Contents) { |
97 | auto &S = getParent()->ContentStorage; |
98 | if (ContentStart + Contents.size() > ContentEnd) { |
99 | ContentStart = S.size(); |
100 | S.resize_for_overwrite(N: S.size() + Contents.size()); |
101 | } |
102 | ContentEnd = ContentStart + Contents.size(); |
103 | llvm::copy(Range&: Contents, Out: S.begin() + ContentStart); |
104 | } |
105 | |
106 | void MCEncodedFragment::addFixup(MCFixup Fixup) { appendFixups(Fixups: {Fixup}); } |
107 | |
108 | void MCEncodedFragment::appendFixups(ArrayRef<MCFixup> Fixups) { |
109 | auto &S = getParent()->FixupStorage; |
110 | if (LLVM_UNLIKELY(FixupEnd != S.size())) { |
111 | // Move the elements to the end. Reserve space to avoid invalidating |
112 | // S.begin()+I for `append`. |
113 | auto Size = FixupEnd - FixupStart; |
114 | auto I = std::exchange(obj&: FixupStart, new_val: S.size()); |
115 | S.reserve(N: S.size() + Size); |
116 | S.append(in_start: S.begin() + I, in_end: S.begin() + I + Size); |
117 | } |
118 | S.append(in_start: Fixups.begin(), in_end: Fixups.end()); |
119 | FixupEnd = S.size(); |
120 | } |
121 | |
122 | void MCEncodedFragment::setFixups(ArrayRef<MCFixup> Fixups) { |
123 | auto &S = getParent()->FixupStorage; |
124 | if (FixupStart + Fixups.size() > FixupEnd) { |
125 | FixupStart = S.size(); |
126 | S.resize_for_overwrite(N: S.size() + Fixups.size()); |
127 | } |
128 | FixupEnd = FixupStart + Fixups.size(); |
129 | llvm::copy(Range&: Fixups, Out: S.begin() + FixupStart); |
130 | } |
131 | |