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 SmallRODataSection = 36 getContext().getELFSection(".srodata", ELF::SHT_PROGBITS, ELF::SHF_ALLOC); 37 SmallROData4Section = getContext().getELFSection( 38 ".srodata.cst4", ELF::SHT_PROGBITS, ELF::SHF_ALLOC | ELF::SHF_MERGE, 4); 39 SmallROData8Section = getContext().getELFSection( 40 ".srodata.cst8", ELF::SHT_PROGBITS, ELF::SHF_ALLOC | ELF::SHF_MERGE, 8); 41 SmallROData16Section = getContext().getELFSection( 42 ".srodata.cst16", ELF::SHT_PROGBITS, ELF::SHF_ALLOC | ELF::SHF_MERGE, 16); 43 SmallROData32Section = getContext().getELFSection( 44 ".srodata.cst32", ELF::SHT_PROGBITS, ELF::SHF_ALLOC | ELF::SHF_MERGE, 32); 45 } 46 47 const MCExpr *RISCVELFTargetObjectFile::getIndirectSymViaGOTPCRel( 48 const GlobalValue *GV, const MCSymbol *Sym, const MCValue &MV, 49 int64_t Offset, MachineModuleInfo *MMI, MCStreamer &Streamer) const { 50 int64_t FinalOffset = Offset + MV.getConstant(); 51 const MCExpr *Res = 52 MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_GOTPCREL, getContext()); 53 const MCExpr *Off = MCConstantExpr::create(FinalOffset, getContext()); 54 return MCBinaryExpr::createAdd(Res, Off, getContext()); 55 } 56 57 // A address must be loaded from a small section if its size is less than the 58 // small section size threshold. Data in this section could be addressed by 59 // using gp_rel operator. 60 bool RISCVELFTargetObjectFile::isInSmallSection(uint64_t Size) const { 61 // gcc has traditionally not treated zero-sized objects as small data, so this 62 // is effectively part of the ABI. 63 return Size > 0 && Size <= SSThreshold; 64 } 65 66 // Return true if this global address should be placed into small data/bss 67 // section. 68 bool RISCVELFTargetObjectFile::isGlobalInSmallSection( 69 const GlobalObject *GO, const TargetMachine &TM) const { 70 // Only global variables, not functions. 71 const GlobalVariable *GVA = dyn_cast<GlobalVariable>(GO); 72 if (!GVA) 73 return false; 74 75 // If the variable has an explicit section, it is placed in that section. 76 if (GVA->hasSection()) { 77 StringRef Section = GVA->getSection(); 78 79 // Explicitly placing any variable in the small data section overrides 80 // the global -G value. 81 if (Section == ".sdata" || Section == ".sbss") 82 return true; 83 84 // Otherwise reject putting the variable to small section if it has an 85 // explicit section name. 86 return false; 87 } 88 89 if (((GVA->hasExternalLinkage() && GVA->isDeclaration()) || 90 GVA->hasCommonLinkage())) 91 return false; 92 93 Type *Ty = GVA->getValueType(); 94 // It is possible that the type of the global is unsized, i.e. a declaration 95 // of a extern struct. In this case don't presume it is in the small data 96 // section. This happens e.g. when building the FreeBSD kernel. 97 if (!Ty->isSized()) 98 return false; 99 100 return isInSmallSection( 101 GVA->getParent()->getDataLayout().getTypeAllocSize(Ty)); 102 } 103 104 MCSection *RISCVELFTargetObjectFile::SelectSectionForGlobal( 105 const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { 106 // Handle Small Section classification here. 107 if (Kind.isBSS() && isGlobalInSmallSection(GO, TM)) 108 return SmallBSSSection; 109 if (Kind.isData() && isGlobalInSmallSection(GO, TM)) 110 return SmallDataSection; 111 112 // Otherwise, we work the same as ELF. 113 return TargetLoweringObjectFileELF::SelectSectionForGlobal(GO, Kind, TM); 114 } 115 116 void RISCVELFTargetObjectFile::getModuleMetadata(Module &M) { 117 TargetLoweringObjectFileELF::getModuleMetadata(M); 118 SmallVector<Module::ModuleFlagEntry, 8> ModuleFlags; 119 M.getModuleFlagsMetadata(ModuleFlags); 120 121 for (const auto &MFE : ModuleFlags) { 122 StringRef Key = MFE.Key->getString(); 123 if (Key == "SmallDataLimit") { 124 SSThreshold = mdconst::extract<ConstantInt>(MFE.Val)->getZExtValue(); 125 break; 126 } 127 } 128 } 129 130 /// Return true if this constant should be placed into small data section. 131 bool RISCVELFTargetObjectFile::isConstantInSmallSection( 132 const DataLayout &DL, const Constant *CN) const { 133 return isInSmallSection(DL.getTypeAllocSize(CN->getType())); 134 } 135 136 MCSection *RISCVELFTargetObjectFile::getSectionForConstant( 137 const DataLayout &DL, SectionKind Kind, const Constant *C, 138 Align &Alignment) const { 139 if (isConstantInSmallSection(DL, C)) { 140 if (Kind.isMergeableConst4()) 141 return SmallROData4Section; 142 if (Kind.isMergeableConst8()) 143 return SmallROData8Section; 144 if (Kind.isMergeableConst16()) 145 return SmallROData16Section; 146 if (Kind.isMergeableConst32()) 147 return SmallROData32Section; 148 // LLVM only generate up to .rodata.cst32, and use .rodata section if more 149 // than 32 bytes, so just use .srodata here. 150 return SmallRODataSection; 151 } 152 153 // Otherwise, we work the same as ELF. 154 return TargetLoweringObjectFileELF::getSectionForConstant(DL, Kind, C, 155 Alignment); 156 } 157