1//===-- MipsTargetObjectFile.cpp - Mips Object Files ----------------------===//
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 "MipsTargetObjectFile.h"
10#include "MCTargetDesc/MipsMCAsmInfo.h"
11#include "MipsSubtarget.h"
12#include "MipsTargetMachine.h"
13#include "llvm/BinaryFormat/ELF.h"
14#include "llvm/IR/DataLayout.h"
15#include "llvm/IR/GlobalVariable.h"
16#include "llvm/MC/MCContext.h"
17#include "llvm/MC/MCSectionELF.h"
18#include "llvm/Target/TargetMachine.h"
19using namespace llvm;
20
21void MipsTargetObjectFile::initialize(MCContext &Ctx, const TargetMachine &TM,
22 const Module &M) {
23 TargetLoweringObjectFileELF::initialize(Ctx, TM, M);
24
25 SmallDataSection = getContext().getELFSection(
26 Section: ".sdata", Type: ELF::SHT_PROGBITS,
27 Flags: ELF::SHF_WRITE | ELF::SHF_ALLOC | ELF::SHF_MIPS_GPREL);
28
29 SmallBSSSection = getContext().getELFSection(Section: ".sbss", Type: ELF::SHT_NOBITS,
30 Flags: ELF::SHF_WRITE | ELF::SHF_ALLOC |
31 ELF::SHF_MIPS_GPREL);
32}
33
34// A address must be loaded from a small section if its size is less than the
35// small section size threshold. Data in this section must be addressed using
36// gp_rel operator.
37static bool isInSmallSection(const MipsOptions &CLOpts, uint64_t Size) {
38 // gcc has traditionally not treated zero-sized objects as small data, so this
39 // is effectively part of the ABI.
40 return Size > 0 && Size <= CLOpts.ssection_threshold;
41}
42
43/// Return true if this global address should be placed into small data/bss
44/// section.
45bool MipsTargetObjectFile::IsGlobalInSmallSection(
46 const GlobalObject *GO) const {
47 // We first check the case where global is a declaration, because finding
48 // section kind using getKindForGlobal() is only allowed for global
49 // definitions.
50 if (GO->isDeclaration() || GO->hasAvailableExternallyLinkage())
51 return IsGlobalInSmallSectionImpl(GO);
52
53 return IsGlobalInSmallSection(GO, Kind: getKindForGlobal(GO, TM: *TM));
54}
55
56/// Return true if this global address should be placed into small data/bss
57/// section.
58bool MipsTargetObjectFile::IsGlobalInSmallSection(const GlobalObject *GO,
59 SectionKind Kind) const {
60 return IsGlobalInSmallSectionImpl(GO) &&
61 (Kind.isData() || Kind.isBSS() || Kind.isCommon() ||
62 Kind.isReadOnly());
63}
64
65/// Return true if this global address should be placed into small data/bss
66/// section. This method does all the work, except for checking the section
67/// kind.
68bool MipsTargetObjectFile::IsGlobalInSmallSectionImpl(
69 const GlobalObject *GO) const {
70 const MipsOptions &CLOpts =
71 static_cast<const MipsTargetMachine *>(TM)->getCLOpts();
72 // Only global variables, not functions.
73 const GlobalVariable *GVA = dyn_cast<GlobalVariable>(Val: GO);
74 if (!GVA)
75 return false;
76
77 // If the variable has an explicit section, it is placed in that section but
78 // it's addressing mode may change.
79 if (GVA->hasSection()) {
80 StringRef Section = GVA->getSection();
81
82 // Explicitly placing any variable in the small data section overrides
83 // the global -G value.
84 if (Section == ".sdata" || Section == ".sbss")
85 return true;
86
87 // Otherwise reject accessing it through the gp pointer. There are some
88 // historic cases which GCC doesn't appear to respect any more. These
89 // are .lit4, .lit8 and .srdata. For the moment reject these as well.
90 return false;
91 }
92
93 // Implicit global placement follows the default subtarget, independently of
94 // the features of the functions that reference the global. Explicit small
95 // sections above also allow GP-relative accesses from functions that enable
96 // them when the default subtarget does not.
97 if (!UseSmallSection)
98 return false;
99
100 // Enforce -mlocal-sdata.
101 if (!CLOpts.mlocal_sdata && GVA->hasLocalLinkage())
102 return false;
103
104 // Enforce -mextern-sdata.
105 if (!CLOpts.mextern_sdata &&
106 ((GVA->hasExternalLinkage() && GVA->isDeclaration()) ||
107 GVA->hasCommonLinkage()))
108 return false;
109
110 // Enforce -membedded-data.
111 if (CLOpts.membedded_data && GVA->isConstant())
112 return false;
113
114 Type *Ty = GVA->getValueType();
115
116 // It is possible that the type of the global is unsized, i.e. a declaration
117 // of a extern struct. In this case don't presume it is in the small data
118 // section. This happens e.g. when building the FreeBSD kernel.
119 if (!Ty->isSized())
120 return false;
121
122 return isInSmallSection(CLOpts, Size: GVA->getDataLayout().getTypeAllocSize(Ty));
123}
124
125MCSection *MipsTargetObjectFile::SelectSectionForGlobal(
126 const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
127 // TODO: Could also support "weak" symbols as well with ".gnu.linkonce.s.*"
128 // sections?
129
130 // Handle Small Section classification here.
131 if (IsGlobalInSmallSection(GO, Kind)) {
132 if (Kind.isBSS())
133 return SmallBSSSection;
134 if (Kind.isData() || Kind.isReadOnly())
135 return SmallDataSection;
136 }
137
138 // Otherwise, we work the same as ELF.
139 return TargetLoweringObjectFileELF::SelectSectionForGlobal(GO, Kind, TM);
140}
141
142/// Return true if this constant should be placed into small data section.
143bool MipsTargetObjectFile::IsConstantInSmallSection(const DataLayout &DL,
144 const Constant *CN,
145 const Function *F) const {
146 bool UseSmallSection =
147 F ? TM->getSubtarget<MipsSubtarget>(F: *F).useSmallSection()
148 : this->UseSmallSection;
149 const MipsOptions &CLOpts =
150 static_cast<const MipsTargetMachine *>(TM)->getCLOpts();
151 return UseSmallSection && CN && CLOpts.mlocal_sdata &&
152 isInSmallSection(CLOpts, Size: DL.getTypeAllocSize(Ty: CN->getType()));
153}
154
155/// Return true if this constant should be placed into small data section.
156MCSection *MipsTargetObjectFile::getSectionForConstant(
157 const DataLayout &DL, SectionKind Kind, const Constant *C, Align &Alignment,
158 const Function *F) const {
159 if (IsConstantInSmallSection(DL, CN: C, F))
160 return SmallDataSection;
161
162 // Otherwise, we work the same as ELF.
163 return TargetLoweringObjectFileELF::getSectionForConstant(DL, Kind, C,
164 Alignment, F);
165}
166
167const MCExpr *
168MipsTargetObjectFile::getDebugThreadLocalSymbol(const MCSymbol *Sym) const {
169 const MCExpr *Expr = MCSymbolRefExpr::create(Symbol: Sym, Ctx&: getContext());
170 Expr = MCBinaryExpr::createAdd(
171 LHS: Expr, RHS: MCConstantExpr::create(Value: 0x8000, Ctx&: getContext()), Ctx&: getContext());
172 return MCSpecifierExpr::create(Expr, S: Mips::S_DTPREL, Ctx&: getContext());
173}
174