106c3fb27SDimitry 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" 1006c3fb27SDimitry 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" 15*7a6dacacSDimitry Andric #include "llvm/MC/MCValue.h" 160b57cec5SDimitry Andric 170b57cec5SDimitry Andric using namespace llvm; 180b57cec5SDimitry Andric 1906c3fb27SDimitry Andric unsigned RISCVELFTargetObjectFile::getTextSectionAlignment() const { 2006c3fb27SDimitry Andric return RISCVMCObjectFileInfo::getTextSectionAlignment( 2106c3fb27SDimitry Andric *getContext().getSubtargetInfo()); 2206c3fb27SDimitry Andric } 2306c3fb27SDimitry Andric 240b57cec5SDimitry Andric void RISCVELFTargetObjectFile::Initialize(MCContext &Ctx, 250b57cec5SDimitry Andric const TargetMachine &TM) { 260b57cec5SDimitry Andric TargetLoweringObjectFileELF::Initialize(Ctx, TM); 270b57cec5SDimitry Andric 2806c3fb27SDimitry Andric PLTRelativeVariantKind = MCSymbolRefExpr::VK_PLT; 29*7a6dacacSDimitry Andric SupportIndirectSymViaGOTPCRel = true; 3006c3fb27SDimitry Andric 310b57cec5SDimitry Andric SmallDataSection = getContext().getELFSection( 320b57cec5SDimitry Andric ".sdata", ELF::SHT_PROGBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC); 330b57cec5SDimitry Andric SmallBSSSection = getContext().getELFSection(".sbss", ELF::SHT_NOBITS, 340b57cec5SDimitry Andric ELF::SHF_WRITE | ELF::SHF_ALLOC); 350b57cec5SDimitry Andric } 360b57cec5SDimitry Andric 37*7a6dacacSDimitry Andric const MCExpr *RISCVELFTargetObjectFile::getIndirectSymViaGOTPCRel( 38*7a6dacacSDimitry Andric const GlobalValue *GV, const MCSymbol *Sym, const MCValue &MV, 39*7a6dacacSDimitry Andric int64_t Offset, MachineModuleInfo *MMI, MCStreamer &Streamer) const { 40*7a6dacacSDimitry Andric int64_t FinalOffset = Offset + MV.getConstant(); 41*7a6dacacSDimitry Andric const MCExpr *Res = 42*7a6dacacSDimitry Andric MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_GOTPCREL, getContext()); 43*7a6dacacSDimitry Andric const MCExpr *Off = MCConstantExpr::create(FinalOffset, getContext()); 44*7a6dacacSDimitry Andric return MCBinaryExpr::createAdd(Res, Off, getContext()); 45*7a6dacacSDimitry Andric } 46*7a6dacacSDimitry Andric 470b57cec5SDimitry Andric // A address must be loaded from a small section if its size is less than the 480b57cec5SDimitry Andric // small section size threshold. Data in this section could be addressed by 490b57cec5SDimitry Andric // using gp_rel operator. 500b57cec5SDimitry Andric bool RISCVELFTargetObjectFile::isInSmallSection(uint64_t Size) const { 510b57cec5SDimitry Andric // gcc has traditionally not treated zero-sized objects as small data, so this 520b57cec5SDimitry Andric // is effectively part of the ABI. 530b57cec5SDimitry Andric return Size > 0 && Size <= SSThreshold; 540b57cec5SDimitry Andric } 550b57cec5SDimitry Andric 560b57cec5SDimitry Andric // Return true if this global address should be placed into small data/bss 570b57cec5SDimitry Andric // section. 580b57cec5SDimitry Andric bool RISCVELFTargetObjectFile::isGlobalInSmallSection( 590b57cec5SDimitry Andric const GlobalObject *GO, const TargetMachine &TM) const { 600b57cec5SDimitry Andric // Only global variables, not functions. 610b57cec5SDimitry Andric const GlobalVariable *GVA = dyn_cast<GlobalVariable>(GO); 620b57cec5SDimitry Andric if (!GVA) 630b57cec5SDimitry Andric return false; 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric // If the variable has an explicit section, it is placed in that section. 660b57cec5SDimitry Andric if (GVA->hasSection()) { 670b57cec5SDimitry Andric StringRef Section = GVA->getSection(); 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric // Explicitly placing any variable in the small data section overrides 700b57cec5SDimitry Andric // the global -G value. 710b57cec5SDimitry Andric if (Section == ".sdata" || Section == ".sbss") 720b57cec5SDimitry Andric return true; 730b57cec5SDimitry Andric 740b57cec5SDimitry Andric // Otherwise reject putting the variable to small section if it has an 750b57cec5SDimitry Andric // explicit section name. 760b57cec5SDimitry Andric return false; 770b57cec5SDimitry Andric } 780b57cec5SDimitry Andric 790b57cec5SDimitry Andric if (((GVA->hasExternalLinkage() && GVA->isDeclaration()) || 800b57cec5SDimitry Andric GVA->hasCommonLinkage())) 810b57cec5SDimitry Andric return false; 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric Type *Ty = GVA->getValueType(); 840b57cec5SDimitry Andric // It is possible that the type of the global is unsized, i.e. a declaration 850b57cec5SDimitry Andric // of a extern struct. In this case don't presume it is in the small data 860b57cec5SDimitry Andric // section. This happens e.g. when building the FreeBSD kernel. 870b57cec5SDimitry Andric if (!Ty->isSized()) 880b57cec5SDimitry Andric return false; 890b57cec5SDimitry Andric 900b57cec5SDimitry Andric return isInSmallSection( 910b57cec5SDimitry Andric GVA->getParent()->getDataLayout().getTypeAllocSize(Ty)); 920b57cec5SDimitry Andric } 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric MCSection *RISCVELFTargetObjectFile::SelectSectionForGlobal( 950b57cec5SDimitry Andric const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { 960b57cec5SDimitry Andric // Handle Small Section classification here. 970b57cec5SDimitry Andric if (Kind.isBSS() && isGlobalInSmallSection(GO, TM)) 980b57cec5SDimitry Andric return SmallBSSSection; 990b57cec5SDimitry Andric if (Kind.isData() && isGlobalInSmallSection(GO, TM)) 1000b57cec5SDimitry Andric return SmallDataSection; 1010b57cec5SDimitry Andric 1020b57cec5SDimitry Andric // Otherwise, we work the same as ELF. 1030b57cec5SDimitry Andric return TargetLoweringObjectFileELF::SelectSectionForGlobal(GO, Kind, TM); 1040b57cec5SDimitry Andric } 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric void RISCVELFTargetObjectFile::getModuleMetadata(Module &M) { 107fe6060f1SDimitry Andric TargetLoweringObjectFileELF::getModuleMetadata(M); 1080b57cec5SDimitry Andric SmallVector<Module::ModuleFlagEntry, 8> ModuleFlags; 1090b57cec5SDimitry Andric M.getModuleFlagsMetadata(ModuleFlags); 1100b57cec5SDimitry Andric 1110b57cec5SDimitry Andric for (const auto &MFE : ModuleFlags) { 1120b57cec5SDimitry Andric StringRef Key = MFE.Key->getString(); 1130b57cec5SDimitry Andric if (Key == "SmallDataLimit") { 1140b57cec5SDimitry Andric SSThreshold = mdconst::extract<ConstantInt>(MFE.Val)->getZExtValue(); 1150b57cec5SDimitry Andric break; 1160b57cec5SDimitry Andric } 1170b57cec5SDimitry Andric } 1180b57cec5SDimitry Andric } 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric /// Return true if this constant should be placed into small data section. 1210b57cec5SDimitry Andric bool RISCVELFTargetObjectFile::isConstantInSmallSection( 1220b57cec5SDimitry Andric const DataLayout &DL, const Constant *CN) const { 1230b57cec5SDimitry Andric return isInSmallSection(DL.getTypeAllocSize(CN->getType())); 1240b57cec5SDimitry Andric } 1250b57cec5SDimitry Andric 1260b57cec5SDimitry Andric MCSection *RISCVELFTargetObjectFile::getSectionForConstant( 1270b57cec5SDimitry Andric const DataLayout &DL, SectionKind Kind, const Constant *C, 1285ffd83dbSDimitry Andric Align &Alignment) const { 1290b57cec5SDimitry Andric if (isConstantInSmallSection(DL, C)) 1300b57cec5SDimitry Andric return SmallDataSection; 1310b57cec5SDimitry Andric 1320b57cec5SDimitry Andric // Otherwise, we work the same as ELF. 1335ffd83dbSDimitry Andric return TargetLoweringObjectFileELF::getSectionForConstant(DL, Kind, C, 1345ffd83dbSDimitry Andric Alignment); 1350b57cec5SDimitry Andric } 136