1336809Sdim//===-- RISCVTargetObjectFile.cpp - RISCV Object Info -----------------===// 2336809Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6336809Sdim// 7336809Sdim//===----------------------------------------------------------------------===// 8336809Sdim 9336809Sdim#include "RISCVTargetObjectFile.h" 10336809Sdim#include "RISCVTargetMachine.h" 11353358Sdim#include "llvm/BinaryFormat/ELF.h" 12353358Sdim#include "llvm/MC/MCContext.h" 13353358Sdim#include "llvm/MC/MCSectionELF.h" 14336809Sdim 15336809Sdimusing namespace llvm; 16336809Sdim 17336809Sdimvoid RISCVELFTargetObjectFile::Initialize(MCContext &Ctx, 18336809Sdim const TargetMachine &TM) { 19336809Sdim TargetLoweringObjectFileELF::Initialize(Ctx, TM); 20336809Sdim InitializeELF(TM.Options.UseInitArray); 21353358Sdim 22353358Sdim SmallDataSection = getContext().getELFSection( 23353358Sdim ".sdata", ELF::SHT_PROGBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC); 24353358Sdim SmallBSSSection = getContext().getELFSection(".sbss", ELF::SHT_NOBITS, 25353358Sdim ELF::SHF_WRITE | ELF::SHF_ALLOC); 26336809Sdim} 27353358Sdim 28353358Sdim// A address must be loaded from a small section if its size is less than the 29353358Sdim// small section size threshold. Data in this section could be addressed by 30353358Sdim// using gp_rel operator. 31353358Sdimbool RISCVELFTargetObjectFile::isInSmallSection(uint64_t Size) const { 32353358Sdim // gcc has traditionally not treated zero-sized objects as small data, so this 33353358Sdim // is effectively part of the ABI. 34353358Sdim return Size > 0 && Size <= SSThreshold; 35353358Sdim} 36353358Sdim 37353358Sdim// Return true if this global address should be placed into small data/bss 38353358Sdim// section. 39353358Sdimbool RISCVELFTargetObjectFile::isGlobalInSmallSection( 40353358Sdim const GlobalObject *GO, const TargetMachine &TM) const { 41353358Sdim // Only global variables, not functions. 42353358Sdim const GlobalVariable *GVA = dyn_cast<GlobalVariable>(GO); 43353358Sdim if (!GVA) 44353358Sdim return false; 45353358Sdim 46353358Sdim // If the variable has an explicit section, it is placed in that section. 47353358Sdim if (GVA->hasSection()) { 48353358Sdim StringRef Section = GVA->getSection(); 49353358Sdim 50353358Sdim // Explicitly placing any variable in the small data section overrides 51353358Sdim // the global -G value. 52353358Sdim if (Section == ".sdata" || Section == ".sbss") 53353358Sdim return true; 54353358Sdim 55353358Sdim // Otherwise reject putting the variable to small section if it has an 56353358Sdim // explicit section name. 57353358Sdim return false; 58353358Sdim } 59353358Sdim 60353358Sdim if (((GVA->hasExternalLinkage() && GVA->isDeclaration()) || 61353358Sdim GVA->hasCommonLinkage())) 62353358Sdim return false; 63353358Sdim 64353358Sdim Type *Ty = GVA->getValueType(); 65353358Sdim // It is possible that the type of the global is unsized, i.e. a declaration 66353358Sdim // of a extern struct. In this case don't presume it is in the small data 67353358Sdim // section. This happens e.g. when building the FreeBSD kernel. 68353358Sdim if (!Ty->isSized()) 69353358Sdim return false; 70353358Sdim 71353358Sdim return isInSmallSection( 72353358Sdim GVA->getParent()->getDataLayout().getTypeAllocSize(Ty)); 73353358Sdim} 74353358Sdim 75353358SdimMCSection *RISCVELFTargetObjectFile::SelectSectionForGlobal( 76353358Sdim const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { 77353358Sdim // Handle Small Section classification here. 78353358Sdim if (Kind.isBSS() && isGlobalInSmallSection(GO, TM)) 79353358Sdim return SmallBSSSection; 80353358Sdim if (Kind.isData() && isGlobalInSmallSection(GO, TM)) 81353358Sdim return SmallDataSection; 82353358Sdim 83353358Sdim // Otherwise, we work the same as ELF. 84353358Sdim return TargetLoweringObjectFileELF::SelectSectionForGlobal(GO, Kind, TM); 85353358Sdim} 86353358Sdim 87353358Sdimvoid RISCVELFTargetObjectFile::getModuleMetadata(Module &M) { 88353358Sdim SmallVector<Module::ModuleFlagEntry, 8> ModuleFlags; 89353358Sdim M.getModuleFlagsMetadata(ModuleFlags); 90353358Sdim 91353358Sdim for (const auto &MFE : ModuleFlags) { 92353358Sdim StringRef Key = MFE.Key->getString(); 93353358Sdim if (Key == "SmallDataLimit") { 94353358Sdim SSThreshold = mdconst::extract<ConstantInt>(MFE.Val)->getZExtValue(); 95353358Sdim break; 96353358Sdim } 97353358Sdim } 98353358Sdim} 99353358Sdim 100353358Sdim/// Return true if this constant should be placed into small data section. 101353358Sdimbool RISCVELFTargetObjectFile::isConstantInSmallSection( 102353358Sdim const DataLayout &DL, const Constant *CN) const { 103353358Sdim return isInSmallSection(DL.getTypeAllocSize(CN->getType())); 104353358Sdim} 105353358Sdim 106353358SdimMCSection *RISCVELFTargetObjectFile::getSectionForConstant( 107353358Sdim const DataLayout &DL, SectionKind Kind, const Constant *C, 108353358Sdim unsigned &Align) const { 109353358Sdim if (isConstantInSmallSection(DL, C)) 110353358Sdim return SmallDataSection; 111353358Sdim 112353358Sdim // Otherwise, we work the same as ELF. 113353358Sdim return TargetLoweringObjectFileELF::getSectionForConstant(DL, Kind, C, Align); 114353358Sdim} 115