1*06c3fb27SDimitry Andric //===-- RISCVTargetObjectFile.cpp - RISC-V Object Info --------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "RISCVTargetObjectFile.h" 10*06c3fb27SDimitry Andric #include "MCTargetDesc/RISCVMCObjectFileInfo.h" 110b57cec5SDimitry Andric #include "RISCVTargetMachine.h" 120b57cec5SDimitry Andric #include "llvm/BinaryFormat/ELF.h" 130b57cec5SDimitry Andric #include "llvm/MC/MCContext.h" 140b57cec5SDimitry Andric #include "llvm/MC/MCSectionELF.h" 150b57cec5SDimitry Andric 160b57cec5SDimitry Andric using namespace llvm; 170b57cec5SDimitry Andric 18*06c3fb27SDimitry Andric unsigned RISCVELFTargetObjectFile::getTextSectionAlignment() const { 19*06c3fb27SDimitry Andric return RISCVMCObjectFileInfo::getTextSectionAlignment( 20*06c3fb27SDimitry Andric *getContext().getSubtargetInfo()); 21*06c3fb27SDimitry Andric } 22*06c3fb27SDimitry Andric 230b57cec5SDimitry Andric void RISCVELFTargetObjectFile::Initialize(MCContext &Ctx, 240b57cec5SDimitry Andric const TargetMachine &TM) { 250b57cec5SDimitry Andric TargetLoweringObjectFileELF::Initialize(Ctx, TM); 260b57cec5SDimitry Andric 27*06c3fb27SDimitry Andric PLTRelativeVariantKind = MCSymbolRefExpr::VK_PLT; 28*06c3fb27SDimitry Andric 290b57cec5SDimitry Andric SmallDataSection = getContext().getELFSection( 300b57cec5SDimitry Andric ".sdata", ELF::SHT_PROGBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC); 310b57cec5SDimitry Andric SmallBSSSection = getContext().getELFSection(".sbss", ELF::SHT_NOBITS, 320b57cec5SDimitry Andric ELF::SHF_WRITE | ELF::SHF_ALLOC); 330b57cec5SDimitry Andric } 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric // A address must be loaded from a small section if its size is less than the 360b57cec5SDimitry Andric // small section size threshold. Data in this section could be addressed by 370b57cec5SDimitry Andric // using gp_rel operator. 380b57cec5SDimitry Andric bool RISCVELFTargetObjectFile::isInSmallSection(uint64_t Size) const { 390b57cec5SDimitry Andric // gcc has traditionally not treated zero-sized objects as small data, so this 400b57cec5SDimitry Andric // is effectively part of the ABI. 410b57cec5SDimitry Andric return Size > 0 && Size <= SSThreshold; 420b57cec5SDimitry Andric } 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric // Return true if this global address should be placed into small data/bss 450b57cec5SDimitry Andric // section. 460b57cec5SDimitry Andric bool RISCVELFTargetObjectFile::isGlobalInSmallSection( 470b57cec5SDimitry Andric const GlobalObject *GO, const TargetMachine &TM) const { 480b57cec5SDimitry Andric // Only global variables, not functions. 490b57cec5SDimitry Andric const GlobalVariable *GVA = dyn_cast<GlobalVariable>(GO); 500b57cec5SDimitry Andric if (!GVA) 510b57cec5SDimitry Andric return false; 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric // If the variable has an explicit section, it is placed in that section. 540b57cec5SDimitry Andric if (GVA->hasSection()) { 550b57cec5SDimitry Andric StringRef Section = GVA->getSection(); 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric // Explicitly placing any variable in the small data section overrides 580b57cec5SDimitry Andric // the global -G value. 590b57cec5SDimitry Andric if (Section == ".sdata" || Section == ".sbss") 600b57cec5SDimitry Andric return true; 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric // Otherwise reject putting the variable to small section if it has an 630b57cec5SDimitry Andric // explicit section name. 640b57cec5SDimitry Andric return false; 650b57cec5SDimitry Andric } 660b57cec5SDimitry Andric 670b57cec5SDimitry Andric if (((GVA->hasExternalLinkage() && GVA->isDeclaration()) || 680b57cec5SDimitry Andric GVA->hasCommonLinkage())) 690b57cec5SDimitry Andric return false; 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric Type *Ty = GVA->getValueType(); 720b57cec5SDimitry Andric // It is possible that the type of the global is unsized, i.e. a declaration 730b57cec5SDimitry Andric // of a extern struct. In this case don't presume it is in the small data 740b57cec5SDimitry Andric // section. This happens e.g. when building the FreeBSD kernel. 750b57cec5SDimitry Andric if (!Ty->isSized()) 760b57cec5SDimitry Andric return false; 770b57cec5SDimitry Andric 780b57cec5SDimitry Andric return isInSmallSection( 790b57cec5SDimitry Andric GVA->getParent()->getDataLayout().getTypeAllocSize(Ty)); 800b57cec5SDimitry Andric } 810b57cec5SDimitry Andric 820b57cec5SDimitry Andric MCSection *RISCVELFTargetObjectFile::SelectSectionForGlobal( 830b57cec5SDimitry Andric const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { 840b57cec5SDimitry Andric // Handle Small Section classification here. 850b57cec5SDimitry Andric if (Kind.isBSS() && isGlobalInSmallSection(GO, TM)) 860b57cec5SDimitry Andric return SmallBSSSection; 870b57cec5SDimitry Andric if (Kind.isData() && isGlobalInSmallSection(GO, TM)) 880b57cec5SDimitry Andric return SmallDataSection; 890b57cec5SDimitry Andric 900b57cec5SDimitry Andric // Otherwise, we work the same as ELF. 910b57cec5SDimitry Andric return TargetLoweringObjectFileELF::SelectSectionForGlobal(GO, Kind, TM); 920b57cec5SDimitry Andric } 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric void RISCVELFTargetObjectFile::getModuleMetadata(Module &M) { 95fe6060f1SDimitry Andric TargetLoweringObjectFileELF::getModuleMetadata(M); 960b57cec5SDimitry Andric SmallVector<Module::ModuleFlagEntry, 8> ModuleFlags; 970b57cec5SDimitry Andric M.getModuleFlagsMetadata(ModuleFlags); 980b57cec5SDimitry Andric 990b57cec5SDimitry Andric for (const auto &MFE : ModuleFlags) { 1000b57cec5SDimitry Andric StringRef Key = MFE.Key->getString(); 1010b57cec5SDimitry Andric if (Key == "SmallDataLimit") { 1020b57cec5SDimitry Andric SSThreshold = mdconst::extract<ConstantInt>(MFE.Val)->getZExtValue(); 1030b57cec5SDimitry Andric break; 1040b57cec5SDimitry Andric } 1050b57cec5SDimitry Andric } 1060b57cec5SDimitry Andric } 1070b57cec5SDimitry Andric 1080b57cec5SDimitry Andric /// Return true if this constant should be placed into small data section. 1090b57cec5SDimitry Andric bool RISCVELFTargetObjectFile::isConstantInSmallSection( 1100b57cec5SDimitry Andric const DataLayout &DL, const Constant *CN) const { 1110b57cec5SDimitry Andric return isInSmallSection(DL.getTypeAllocSize(CN->getType())); 1120b57cec5SDimitry Andric } 1130b57cec5SDimitry Andric 1140b57cec5SDimitry Andric MCSection *RISCVELFTargetObjectFile::getSectionForConstant( 1150b57cec5SDimitry Andric const DataLayout &DL, SectionKind Kind, const Constant *C, 1165ffd83dbSDimitry Andric Align &Alignment) const { 1170b57cec5SDimitry Andric if (isConstantInSmallSection(DL, C)) 1180b57cec5SDimitry Andric return SmallDataSection; 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric // Otherwise, we work the same as ELF. 1215ffd83dbSDimitry Andric return TargetLoweringObjectFileELF::getSectionForConstant(DL, Kind, C, 1225ffd83dbSDimitry Andric Alignment); 1230b57cec5SDimitry Andric } 124