1//===-- RISCVTargetObjectFile.cpp - RISC-V Object Info --------------------===//
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 "RISCVTargetObjectFile.h"
10#include "MCTargetDesc/RISCVMCObjectFileInfo.h"
11#include "RISCVTargetMachine.h"
12#include "llvm/BinaryFormat/ELF.h"
13#include "llvm/IR/Mangler.h"
14#include "llvm/IR/Module.h"
15#include "llvm/MC/MCContext.h"
16#include "llvm/MC/MCSectionELF.h"
17#include "llvm/MC/MCValue.h"
18
19using namespace llvm;
20
21unsigned RISCVELFTargetObjectFile::getTextSectionAlignment() const {
22 return RISCVMCObjectFileInfo::getTextSectionAlignment(
23 STI: *getContext().getSubtargetInfo());
24}
25
26void RISCVELFTargetObjectFile::Initialize(MCContext &Ctx,
27 const TargetMachine &TM) {
28 TargetLoweringObjectFileELF::Initialize(Ctx, TM);
29
30 PLTPCRelativeSpecifier = ELF::R_RISCV_PLT32;
31 SupportIndirectSymViaGOTPCRel = true;
32
33 SmallDataSection = getContext().getELFSection(
34 Section: ".sdata", Type: ELF::SHT_PROGBITS, Flags: ELF::SHF_WRITE | ELF::SHF_ALLOC);
35 SmallBSSSection = getContext().getELFSection(Section: ".sbss", Type: ELF::SHT_NOBITS,
36 Flags: ELF::SHF_WRITE | ELF::SHF_ALLOC);
37 SmallRODataSection =
38 getContext().getELFSection(Section: ".srodata", Type: ELF::SHT_PROGBITS, Flags: ELF::SHF_ALLOC);
39 SmallROData4Section = getContext().getELFSection(
40 Section: ".srodata.cst4", Type: ELF::SHT_PROGBITS, Flags: ELF::SHF_ALLOC | ELF::SHF_MERGE, EntrySize: 4);
41 SmallROData8Section = getContext().getELFSection(
42 Section: ".srodata.cst8", Type: ELF::SHT_PROGBITS, Flags: ELF::SHF_ALLOC | ELF::SHF_MERGE, EntrySize: 8);
43 SmallROData16Section = getContext().getELFSection(
44 Section: ".srodata.cst16", Type: ELF::SHT_PROGBITS, Flags: ELF::SHF_ALLOC | ELF::SHF_MERGE, EntrySize: 16);
45 SmallROData32Section = getContext().getELFSection(
46 Section: ".srodata.cst32", Type: ELF::SHT_PROGBITS, Flags: ELF::SHF_ALLOC | ELF::SHF_MERGE, EntrySize: 32);
47}
48
49const MCExpr *RISCVELFTargetObjectFile::getIndirectSymViaGOTPCRel(
50 const GlobalValue *GV, const MCSymbol *Sym, const MCValue &MV,
51 int64_t Offset, MachineModuleInfo *MMI, MCStreamer &Streamer) const {
52 auto &Ctx = getContext();
53 const MCExpr *Res = MCSymbolRefExpr::create(Symbol: Sym, Ctx);
54 Res = MCBinaryExpr::createAdd(
55 LHS: Res, RHS: MCConstantExpr::create(Value: Offset + MV.getConstant(), Ctx), Ctx);
56 return MCSpecifierExpr::create(Expr: Res, S: ELF::R_RISCV_GOT32_PCREL, Ctx);
57}
58
59bool RISCVELFTargetObjectFile::shouldPutJumpTableInFunctionSection(
60 bool UsesLabelDifference, const Function &F) const {
61 // With the large code model, keep the jump table in the function's section.
62 if (TM->getCodeModel() == CodeModel::Large)
63 return true;
64 return TargetLoweringObjectFileELF::shouldPutJumpTableInFunctionSection(
65 UsesLabelDifference, F);
66}
67
68// A address must be loaded from a small section if its size is less than the
69// small section size threshold. Data in this section could be addressed by
70// using gp_rel operator.
71bool RISCVELFTargetObjectFile::isInSmallSection(uint64_t Size) const {
72 // gcc has traditionally not treated zero-sized objects as small data, so this
73 // is effectively part of the ABI.
74 return Size > 0 && Size <= SSThreshold;
75}
76
77// Return true if this global address should be placed into small data/bss
78// section.
79bool RISCVELFTargetObjectFile::isGlobalInSmallSection(
80 const GlobalObject *GO, const TargetMachine &TM) const {
81 // Only global variables, not functions.
82 const GlobalVariable *GVA = dyn_cast<GlobalVariable>(Val: GO);
83 if (!GVA)
84 return false;
85
86 // If the variable has an explicit section, it is placed in that section.
87 if (GVA->hasSection()) {
88 StringRef Section = GVA->getSection();
89
90 // Explicitly placing any variable in the small data section overrides
91 // the global -G value.
92 if (Section == ".sdata" || Section == ".sbss")
93 return true;
94
95 // Otherwise reject putting the variable to small section if it has an
96 // explicit section name.
97 return false;
98 }
99
100 if (((GVA->hasExternalLinkage() && GVA->isDeclaration()) ||
101 GVA->hasCommonLinkage()))
102 return false;
103
104 Type *Ty = GVA->getValueType();
105 // It is possible that the type of the global is unsized, i.e. a declaration
106 // of a extern struct. In this case don't presume it is in the small data
107 // section. This happens e.g. when building the FreeBSD kernel.
108 if (!Ty->isSized())
109 return false;
110
111 return isInSmallSection(
112 Size: GVA->getDataLayout().getTypeAllocSize(Ty));
113}
114
115MCSection *RISCVELFTargetObjectFile::SelectSectionForGlobal(
116 const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
117 // Handle Small Section classification here.
118 if (isGlobalInSmallSection(GO, TM)) {
119 // Emit to an unique sdata/sbss section when -fdata-section is set.
120 // However, if a symbol has an explicit sdata/sbss section, place it in that
121 // section.
122 bool EmitUniquedSection = TM.getDataSections() && !GO->hasSection();
123
124 if (Kind.isBSS()) {
125 if (EmitUniquedSection) {
126 SmallString<128> Name(".sbss.");
127 Name.append(RHS: GO->getName());
128 return getContext().getELFSection(Section: Name.str(), Type: ELF::SHT_NOBITS,
129 Flags: ELF::SHF_WRITE | ELF::SHF_ALLOC);
130 }
131
132 return SmallBSSSection;
133 }
134
135 if (Kind.isData()) {
136 if (EmitUniquedSection) {
137 SmallString<128> Name(".sdata.");
138 Name.append(RHS: GO->getName());
139 return getContext().getELFSection(Section: Name.str(), Type: ELF::SHT_PROGBITS,
140 Flags: ELF::SHF_WRITE | ELF::SHF_ALLOC);
141 }
142
143 return SmallDataSection;
144 }
145 }
146
147 // Otherwise, we work the same as ELF.
148 return TargetLoweringObjectFileELF::SelectSectionForGlobal(GO, Kind, TM);
149}
150
151void RISCVELFTargetObjectFile::getModuleMetadata(Module &M) {
152 TargetLoweringObjectFileELF::getModuleMetadata(M);
153 SmallVector<Module::ModuleFlagEntry, 8> ModuleFlags;
154 M.getModuleFlagsMetadata(Flags&: ModuleFlags);
155
156 for (const auto &MFE : ModuleFlags) {
157 StringRef Key = MFE.Key->getString();
158 if (Key == "SmallDataLimit") {
159 SSThreshold = mdconst::extract<ConstantInt>(MD: MFE.Val)->getZExtValue();
160 break;
161 }
162 }
163}
164
165/// Return true if this constant should be placed into small data section.
166bool RISCVELFTargetObjectFile::isConstantInSmallSection(
167 const DataLayout &DL, const Constant *CN) const {
168 return isInSmallSection(Size: DL.getTypeAllocSize(Ty: CN->getType()));
169}
170
171MCSection *RISCVELFTargetObjectFile::getSectionForConstant(
172 const DataLayout &DL, SectionKind Kind, const Constant *C, Align &Alignment,
173 const Function *F) const {
174
175 // The large code model has to put constant pools close to the program, so we
176 // put them in the .text section. Large code model doesn't support PIC, so
177 // there should be no dynamic relocations that would require `.data.rel.ro`
178 // (which could be too far away anyway).
179 if (TM->getCodeModel() == CodeModel::Large) {
180 if (F)
181 return SectionForGlobal(GO: F, Kind: SectionKind::getText(), TM: *TM);
182 else
183 return TextSection;
184 }
185
186 if (C && isConstantInSmallSection(DL, CN: C)) {
187 if (Kind.isMergeableConst4())
188 return SmallROData4Section;
189 if (Kind.isMergeableConst8())
190 return SmallROData8Section;
191 if (Kind.isMergeableConst16())
192 return SmallROData16Section;
193 if (Kind.isMergeableConst32())
194 return SmallROData32Section;
195 // LLVM only generate up to .rodata.cst32, and use .rodata section if more
196 // than 32 bytes, so just use .srodata here.
197 return SmallRODataSection;
198 }
199
200 // Otherwise, we work the same as ELF.
201 return TargetLoweringObjectFileELF::getSectionForConstant(DL, Kind, C,
202 Alignment, F);
203}
204
205void RISCVMachOTargetObjectFile::getNameWithPrefix(
206 SmallVectorImpl<char> &OutName, const GlobalValue *GV,
207 const TargetMachine &TM) const {
208 // RISC-V does not use section-relative relocations so any global symbol must
209 // be accessed via at least a linker-private symbol.
210 getMangler().getNameWithPrefix(OutName, GV, /*CannotUsePrivateLabel=*/true);
211}
212