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" 13*0fca6ea1SDimitry Andric #include "llvm/IR/Module.h" 140b57cec5SDimitry Andric #include "llvm/MC/MCContext.h" 150b57cec5SDimitry Andric #include "llvm/MC/MCSectionELF.h" 167a6dacacSDimitry Andric #include "llvm/MC/MCValue.h" 170b57cec5SDimitry Andric 180b57cec5SDimitry Andric using namespace llvm; 190b57cec5SDimitry Andric 2006c3fb27SDimitry Andric unsigned RISCVELFTargetObjectFile::getTextSectionAlignment() const { 2106c3fb27SDimitry Andric return RISCVMCObjectFileInfo::getTextSectionAlignment( 2206c3fb27SDimitry Andric *getContext().getSubtargetInfo()); 2306c3fb27SDimitry Andric } 2406c3fb27SDimitry Andric 250b57cec5SDimitry Andric void RISCVELFTargetObjectFile::Initialize(MCContext &Ctx, 260b57cec5SDimitry Andric const TargetMachine &TM) { 270b57cec5SDimitry Andric TargetLoweringObjectFileELF::Initialize(Ctx, TM); 280b57cec5SDimitry Andric 2906c3fb27SDimitry Andric PLTRelativeVariantKind = MCSymbolRefExpr::VK_PLT; 307a6dacacSDimitry Andric SupportIndirectSymViaGOTPCRel = true; 3106c3fb27SDimitry Andric 320b57cec5SDimitry Andric SmallDataSection = getContext().getELFSection( 330b57cec5SDimitry Andric ".sdata", ELF::SHT_PROGBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC); 340b57cec5SDimitry Andric SmallBSSSection = getContext().getELFSection(".sbss", ELF::SHT_NOBITS, 350b57cec5SDimitry Andric ELF::SHF_WRITE | ELF::SHF_ALLOC); 36*0fca6ea1SDimitry Andric SmallRODataSection = 37*0fca6ea1SDimitry Andric getContext().getELFSection(".srodata", ELF::SHT_PROGBITS, ELF::SHF_ALLOC); 38*0fca6ea1SDimitry Andric SmallROData4Section = getContext().getELFSection( 39*0fca6ea1SDimitry Andric ".srodata.cst4", ELF::SHT_PROGBITS, ELF::SHF_ALLOC | ELF::SHF_MERGE, 4); 40*0fca6ea1SDimitry Andric SmallROData8Section = getContext().getELFSection( 41*0fca6ea1SDimitry Andric ".srodata.cst8", ELF::SHT_PROGBITS, ELF::SHF_ALLOC | ELF::SHF_MERGE, 8); 42*0fca6ea1SDimitry Andric SmallROData16Section = getContext().getELFSection( 43*0fca6ea1SDimitry Andric ".srodata.cst16", ELF::SHT_PROGBITS, ELF::SHF_ALLOC | ELF::SHF_MERGE, 16); 44*0fca6ea1SDimitry Andric SmallROData32Section = getContext().getELFSection( 45*0fca6ea1SDimitry Andric ".srodata.cst32", ELF::SHT_PROGBITS, ELF::SHF_ALLOC | ELF::SHF_MERGE, 32); 460b57cec5SDimitry Andric } 470b57cec5SDimitry Andric 487a6dacacSDimitry Andric const MCExpr *RISCVELFTargetObjectFile::getIndirectSymViaGOTPCRel( 497a6dacacSDimitry Andric const GlobalValue *GV, const MCSymbol *Sym, const MCValue &MV, 507a6dacacSDimitry Andric int64_t Offset, MachineModuleInfo *MMI, MCStreamer &Streamer) const { 517a6dacacSDimitry Andric int64_t FinalOffset = Offset + MV.getConstant(); 527a6dacacSDimitry Andric const MCExpr *Res = 537a6dacacSDimitry Andric MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_GOTPCREL, getContext()); 547a6dacacSDimitry Andric const MCExpr *Off = MCConstantExpr::create(FinalOffset, getContext()); 557a6dacacSDimitry Andric return MCBinaryExpr::createAdd(Res, Off, getContext()); 567a6dacacSDimitry Andric } 577a6dacacSDimitry Andric 580b57cec5SDimitry Andric // A address must be loaded from a small section if its size is less than the 590b57cec5SDimitry Andric // small section size threshold. Data in this section could be addressed by 600b57cec5SDimitry Andric // using gp_rel operator. 610b57cec5SDimitry Andric bool RISCVELFTargetObjectFile::isInSmallSection(uint64_t Size) const { 620b57cec5SDimitry Andric // gcc has traditionally not treated zero-sized objects as small data, so this 630b57cec5SDimitry Andric // is effectively part of the ABI. 640b57cec5SDimitry Andric return Size > 0 && Size <= SSThreshold; 650b57cec5SDimitry Andric } 660b57cec5SDimitry Andric 670b57cec5SDimitry Andric // Return true if this global address should be placed into small data/bss 680b57cec5SDimitry Andric // section. 690b57cec5SDimitry Andric bool RISCVELFTargetObjectFile::isGlobalInSmallSection( 700b57cec5SDimitry Andric const GlobalObject *GO, const TargetMachine &TM) const { 710b57cec5SDimitry Andric // Only global variables, not functions. 720b57cec5SDimitry Andric const GlobalVariable *GVA = dyn_cast<GlobalVariable>(GO); 730b57cec5SDimitry Andric if (!GVA) 740b57cec5SDimitry Andric return false; 750b57cec5SDimitry Andric 760b57cec5SDimitry Andric // If the variable has an explicit section, it is placed in that section. 770b57cec5SDimitry Andric if (GVA->hasSection()) { 780b57cec5SDimitry Andric StringRef Section = GVA->getSection(); 790b57cec5SDimitry Andric 800b57cec5SDimitry Andric // Explicitly placing any variable in the small data section overrides 810b57cec5SDimitry Andric // the global -G value. 820b57cec5SDimitry Andric if (Section == ".sdata" || Section == ".sbss") 830b57cec5SDimitry Andric return true; 840b57cec5SDimitry Andric 850b57cec5SDimitry Andric // Otherwise reject putting the variable to small section if it has an 860b57cec5SDimitry Andric // explicit section name. 870b57cec5SDimitry Andric return false; 880b57cec5SDimitry Andric } 890b57cec5SDimitry Andric 900b57cec5SDimitry Andric if (((GVA->hasExternalLinkage() && GVA->isDeclaration()) || 910b57cec5SDimitry Andric GVA->hasCommonLinkage())) 920b57cec5SDimitry Andric return false; 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric Type *Ty = GVA->getValueType(); 950b57cec5SDimitry Andric // It is possible that the type of the global is unsized, i.e. a declaration 960b57cec5SDimitry Andric // of a extern struct. In this case don't presume it is in the small data 970b57cec5SDimitry Andric // section. This happens e.g. when building the FreeBSD kernel. 980b57cec5SDimitry Andric if (!Ty->isSized()) 990b57cec5SDimitry Andric return false; 1000b57cec5SDimitry Andric 1010b57cec5SDimitry Andric return isInSmallSection( 102*0fca6ea1SDimitry Andric GVA->getDataLayout().getTypeAllocSize(Ty)); 1030b57cec5SDimitry Andric } 1040b57cec5SDimitry Andric 1050b57cec5SDimitry Andric MCSection *RISCVELFTargetObjectFile::SelectSectionForGlobal( 1060b57cec5SDimitry Andric const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { 1070b57cec5SDimitry Andric // Handle Small Section classification here. 1080b57cec5SDimitry Andric if (Kind.isBSS() && isGlobalInSmallSection(GO, TM)) 1090b57cec5SDimitry Andric return SmallBSSSection; 1100b57cec5SDimitry Andric if (Kind.isData() && isGlobalInSmallSection(GO, TM)) 1110b57cec5SDimitry Andric return SmallDataSection; 1120b57cec5SDimitry Andric 1130b57cec5SDimitry Andric // Otherwise, we work the same as ELF. 1140b57cec5SDimitry Andric return TargetLoweringObjectFileELF::SelectSectionForGlobal(GO, Kind, TM); 1150b57cec5SDimitry Andric } 1160b57cec5SDimitry Andric 1170b57cec5SDimitry Andric void RISCVELFTargetObjectFile::getModuleMetadata(Module &M) { 118fe6060f1SDimitry Andric TargetLoweringObjectFileELF::getModuleMetadata(M); 1190b57cec5SDimitry Andric SmallVector<Module::ModuleFlagEntry, 8> ModuleFlags; 1200b57cec5SDimitry Andric M.getModuleFlagsMetadata(ModuleFlags); 1210b57cec5SDimitry Andric 1220b57cec5SDimitry Andric for (const auto &MFE : ModuleFlags) { 1230b57cec5SDimitry Andric StringRef Key = MFE.Key->getString(); 1240b57cec5SDimitry Andric if (Key == "SmallDataLimit") { 1250b57cec5SDimitry Andric SSThreshold = mdconst::extract<ConstantInt>(MFE.Val)->getZExtValue(); 1260b57cec5SDimitry Andric break; 1270b57cec5SDimitry Andric } 1280b57cec5SDimitry Andric } 1290b57cec5SDimitry Andric } 1300b57cec5SDimitry Andric 1310b57cec5SDimitry Andric /// Return true if this constant should be placed into small data section. 1320b57cec5SDimitry Andric bool RISCVELFTargetObjectFile::isConstantInSmallSection( 1330b57cec5SDimitry Andric const DataLayout &DL, const Constant *CN) const { 1340b57cec5SDimitry Andric return isInSmallSection(DL.getTypeAllocSize(CN->getType())); 1350b57cec5SDimitry Andric } 1360b57cec5SDimitry Andric 1370b57cec5SDimitry Andric MCSection *RISCVELFTargetObjectFile::getSectionForConstant( 1380b57cec5SDimitry Andric const DataLayout &DL, SectionKind Kind, const Constant *C, 1395ffd83dbSDimitry Andric Align &Alignment) const { 140*0fca6ea1SDimitry Andric if (isConstantInSmallSection(DL, C)) { 141*0fca6ea1SDimitry Andric if (Kind.isMergeableConst4()) 142*0fca6ea1SDimitry Andric return SmallROData4Section; 143*0fca6ea1SDimitry Andric if (Kind.isMergeableConst8()) 144*0fca6ea1SDimitry Andric return SmallROData8Section; 145*0fca6ea1SDimitry Andric if (Kind.isMergeableConst16()) 146*0fca6ea1SDimitry Andric return SmallROData16Section; 147*0fca6ea1SDimitry Andric if (Kind.isMergeableConst32()) 148*0fca6ea1SDimitry Andric return SmallROData32Section; 149*0fca6ea1SDimitry Andric // LLVM only generate up to .rodata.cst32, and use .rodata section if more 150*0fca6ea1SDimitry Andric // than 32 bytes, so just use .srodata here. 151*0fca6ea1SDimitry Andric return SmallRODataSection; 152*0fca6ea1SDimitry Andric } 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric // Otherwise, we work the same as ELF. 1555ffd83dbSDimitry Andric return TargetLoweringObjectFileELF::getSectionForConstant(DL, Kind, C, 1565ffd83dbSDimitry Andric Alignment); 1570b57cec5SDimitry Andric } 158