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/MC/MCContext.h" 14 #include "llvm/MC/MCSectionELF.h" 15 #include "llvm/MC/MCValue.h" 16 17 using namespace llvm; 18 19 unsigned RISCVELFTargetObjectFile::getTextSectionAlignment() const { 20 return RISCVMCObjectFileInfo::getTextSectionAlignment( 21 *getContext().getSubtargetInfo()); 22 } 23 24 void RISCVELFTargetObjectFile::Initialize(MCContext &Ctx, 25 const TargetMachine &TM) { 26 TargetLoweringObjectFileELF::Initialize(Ctx, TM); 27 28 PLTRelativeVariantKind = MCSymbolRefExpr::VK_PLT; 29 SupportIndirectSymViaGOTPCRel = true; 30 31 SmallDataSection = getContext().getELFSection( 32 ".sdata", ELF::SHT_PROGBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC); 33 SmallBSSSection = getContext().getELFSection(".sbss", ELF::SHT_NOBITS, 34 ELF::SHF_WRITE | ELF::SHF_ALLOC); 35 } 36 37 const MCExpr *RISCVELFTargetObjectFile::getIndirectSymViaGOTPCRel( 38 const GlobalValue *GV, const MCSymbol *Sym, const MCValue &MV, 39 int64_t Offset, MachineModuleInfo *MMI, MCStreamer &Streamer) const { 40 int64_t FinalOffset = Offset + MV.getConstant(); 41 const MCExpr *Res = 42 MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_GOTPCREL, getContext()); 43 const MCExpr *Off = MCConstantExpr::create(FinalOffset, getContext()); 44 return MCBinaryExpr::createAdd(Res, Off, getContext()); 45 } 46 47 // A address must be loaded from a small section if its size is less than the 48 // small section size threshold. Data in this section could be addressed by 49 // using gp_rel operator. 50 bool RISCVELFTargetObjectFile::isInSmallSection(uint64_t Size) const { 51 // gcc has traditionally not treated zero-sized objects as small data, so this 52 // is effectively part of the ABI. 53 return Size > 0 && Size <= SSThreshold; 54 } 55 56 // Return true if this global address should be placed into small data/bss 57 // section. 58 bool RISCVELFTargetObjectFile::isGlobalInSmallSection( 59 const GlobalObject *GO, const TargetMachine &TM) const { 60 // Only global variables, not functions. 61 const GlobalVariable *GVA = dyn_cast<GlobalVariable>(GO); 62 if (!GVA) 63 return false; 64 65 // If the variable has an explicit section, it is placed in that section. 66 if (GVA->hasSection()) { 67 StringRef Section = GVA->getSection(); 68 69 // Explicitly placing any variable in the small data section overrides 70 // the global -G value. 71 if (Section == ".sdata" || Section == ".sbss") 72 return true; 73 74 // Otherwise reject putting the variable to small section if it has an 75 // explicit section name. 76 return false; 77 } 78 79 if (((GVA->hasExternalLinkage() && GVA->isDeclaration()) || 80 GVA->hasCommonLinkage())) 81 return false; 82 83 Type *Ty = GVA->getValueType(); 84 // It is possible that the type of the global is unsized, i.e. a declaration 85 // of a extern struct. In this case don't presume it is in the small data 86 // section. This happens e.g. when building the FreeBSD kernel. 87 if (!Ty->isSized()) 88 return false; 89 90 return isInSmallSection( 91 GVA->getParent()->getDataLayout().getTypeAllocSize(Ty)); 92 } 93 94 MCSection *RISCVELFTargetObjectFile::SelectSectionForGlobal( 95 const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { 96 // Handle Small Section classification here. 97 if (Kind.isBSS() && isGlobalInSmallSection(GO, TM)) 98 return SmallBSSSection; 99 if (Kind.isData() && isGlobalInSmallSection(GO, TM)) 100 return SmallDataSection; 101 102 // Otherwise, we work the same as ELF. 103 return TargetLoweringObjectFileELF::SelectSectionForGlobal(GO, Kind, TM); 104 } 105 106 void RISCVELFTargetObjectFile::getModuleMetadata(Module &M) { 107 TargetLoweringObjectFileELF::getModuleMetadata(M); 108 SmallVector<Module::ModuleFlagEntry, 8> ModuleFlags; 109 M.getModuleFlagsMetadata(ModuleFlags); 110 111 for (const auto &MFE : ModuleFlags) { 112 StringRef Key = MFE.Key->getString(); 113 if (Key == "SmallDataLimit") { 114 SSThreshold = mdconst::extract<ConstantInt>(MFE.Val)->getZExtValue(); 115 break; 116 } 117 } 118 } 119 120 /// Return true if this constant should be placed into small data section. 121 bool RISCVELFTargetObjectFile::isConstantInSmallSection( 122 const DataLayout &DL, const Constant *CN) const { 123 return isInSmallSection(DL.getTypeAllocSize(CN->getType())); 124 } 125 126 MCSection *RISCVELFTargetObjectFile::getSectionForConstant( 127 const DataLayout &DL, SectionKind Kind, const Constant *C, 128 Align &Alignment) const { 129 if (isConstantInSmallSection(DL, C)) 130 return SmallDataSection; 131 132 // Otherwise, we work the same as ELF. 133 return TargetLoweringObjectFileELF::getSectionForConstant(DL, Kind, C, 134 Alignment); 135 } 136