10b57cec5SDimitry Andric //===-- MipsTargetObjectFile.cpp - Mips Object Files ----------------------===// 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 "MipsTargetObjectFile.h" 100b57cec5SDimitry Andric #include "MipsSubtarget.h" 110b57cec5SDimitry Andric #include "MipsTargetMachine.h" 120b57cec5SDimitry Andric #include "MCTargetDesc/MipsMCExpr.h" 130b57cec5SDimitry Andric #include "llvm/BinaryFormat/ELF.h" 140b57cec5SDimitry Andric #include "llvm/IR/DataLayout.h" 150b57cec5SDimitry Andric #include "llvm/IR/DerivedTypes.h" 160b57cec5SDimitry Andric #include "llvm/IR/GlobalVariable.h" 170b57cec5SDimitry Andric #include "llvm/MC/MCContext.h" 180b57cec5SDimitry Andric #include "llvm/MC/MCSectionELF.h" 190b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h" 200b57cec5SDimitry Andric #include "llvm/Target/TargetMachine.h" 210b57cec5SDimitry Andric using namespace llvm; 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric static cl::opt<unsigned> 240b57cec5SDimitry Andric SSThreshold("mips-ssection-threshold", cl::Hidden, 250b57cec5SDimitry Andric cl::desc("Small data and bss section threshold size (default=8)"), 260b57cec5SDimitry Andric cl::init(8)); 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric static cl::opt<bool> 290b57cec5SDimitry Andric LocalSData("mlocal-sdata", cl::Hidden, 300b57cec5SDimitry Andric cl::desc("MIPS: Use gp_rel for object-local data."), 310b57cec5SDimitry Andric cl::init(true)); 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric static cl::opt<bool> 340b57cec5SDimitry Andric ExternSData("mextern-sdata", cl::Hidden, 350b57cec5SDimitry Andric cl::desc("MIPS: Use gp_rel for data that is not defined by the " 360b57cec5SDimitry Andric "current object."), 370b57cec5SDimitry Andric cl::init(true)); 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric static cl::opt<bool> 400b57cec5SDimitry Andric EmbeddedData("membedded-data", cl::Hidden, 410b57cec5SDimitry Andric cl::desc("MIPS: Try to allocate variables in the following" 420b57cec5SDimitry Andric " sections if possible: .rodata, .sdata, .data ."), 430b57cec5SDimitry Andric cl::init(false)); 440b57cec5SDimitry Andric 450b57cec5SDimitry Andric void MipsTargetObjectFile::Initialize(MCContext &Ctx, const TargetMachine &TM){ 460b57cec5SDimitry Andric TargetLoweringObjectFileELF::Initialize(Ctx, TM); 470b57cec5SDimitry Andric 480b57cec5SDimitry Andric SmallDataSection = getContext().getELFSection( 490b57cec5SDimitry Andric ".sdata", ELF::SHT_PROGBITS, 500b57cec5SDimitry Andric ELF::SHF_WRITE | ELF::SHF_ALLOC | ELF::SHF_MIPS_GPREL); 510b57cec5SDimitry Andric 520b57cec5SDimitry Andric SmallBSSSection = getContext().getELFSection(".sbss", ELF::SHT_NOBITS, 530b57cec5SDimitry Andric ELF::SHF_WRITE | ELF::SHF_ALLOC | 540b57cec5SDimitry Andric ELF::SHF_MIPS_GPREL); 550b57cec5SDimitry Andric this->TM = &static_cast<const MipsTargetMachine &>(TM); 560b57cec5SDimitry Andric } 570b57cec5SDimitry 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 must be addressed using 600b57cec5SDimitry Andric // gp_rel operator. 610b57cec5SDimitry Andric static bool IsInSmallSection(uint64_t Size) { 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 MipsTargetObjectFile::IsGlobalInSmallSection( 700b57cec5SDimitry Andric const GlobalObject *GO, const TargetMachine &TM) const { 710b57cec5SDimitry Andric // We first check the case where global is a declaration, because finding 720b57cec5SDimitry Andric // section kind using getKindForGlobal() is only allowed for global 730b57cec5SDimitry Andric // definitions. 740b57cec5SDimitry Andric if (GO->isDeclaration() || GO->hasAvailableExternallyLinkage()) 750b57cec5SDimitry Andric return IsGlobalInSmallSectionImpl(GO, TM); 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric return IsGlobalInSmallSection(GO, TM, getKindForGlobal(GO, TM)); 780b57cec5SDimitry Andric } 790b57cec5SDimitry Andric 800b57cec5SDimitry Andric /// Return true if this global address should be placed into small data/bss 810b57cec5SDimitry Andric /// section. 820b57cec5SDimitry Andric bool MipsTargetObjectFile:: 830b57cec5SDimitry Andric IsGlobalInSmallSection(const GlobalObject *GO, const TargetMachine &TM, 840b57cec5SDimitry Andric SectionKind Kind) const { 850b57cec5SDimitry Andric return IsGlobalInSmallSectionImpl(GO, TM) && 860b57cec5SDimitry Andric (Kind.isData() || Kind.isBSS() || Kind.isCommon() || 870b57cec5SDimitry Andric Kind.isReadOnly()); 880b57cec5SDimitry Andric } 890b57cec5SDimitry Andric 900b57cec5SDimitry Andric /// Return true if this global address should be placed into small data/bss 910b57cec5SDimitry Andric /// section. This method does all the work, except for checking the section 920b57cec5SDimitry Andric /// kind. 930b57cec5SDimitry Andric bool MipsTargetObjectFile:: 940b57cec5SDimitry Andric IsGlobalInSmallSectionImpl(const GlobalObject *GO, 950b57cec5SDimitry Andric const TargetMachine &TM) const { 960b57cec5SDimitry Andric const MipsSubtarget &Subtarget = 970b57cec5SDimitry Andric *static_cast<const MipsTargetMachine &>(TM).getSubtargetImpl(); 980b57cec5SDimitry Andric 990b57cec5SDimitry Andric // Return if small section is not available. 1000b57cec5SDimitry Andric if (!Subtarget.useSmallSection()) 1010b57cec5SDimitry Andric return false; 1020b57cec5SDimitry Andric 1030b57cec5SDimitry Andric // Only global variables, not functions. 1040b57cec5SDimitry Andric const GlobalVariable *GVA = dyn_cast<GlobalVariable>(GO); 1050b57cec5SDimitry Andric if (!GVA) 1060b57cec5SDimitry Andric return false; 1070b57cec5SDimitry Andric 1080b57cec5SDimitry Andric // If the variable has an explicit section, it is placed in that section but 1090b57cec5SDimitry Andric // it's addressing mode may change. 1100b57cec5SDimitry Andric if (GVA->hasSection()) { 1110b57cec5SDimitry Andric StringRef Section = GVA->getSection(); 1120b57cec5SDimitry Andric 1130b57cec5SDimitry Andric // Explicitly placing any variable in the small data section overrides 1140b57cec5SDimitry Andric // the global -G value. 1150b57cec5SDimitry Andric if (Section == ".sdata" || Section == ".sbss") 1160b57cec5SDimitry Andric return true; 1170b57cec5SDimitry Andric 1180b57cec5SDimitry Andric // Otherwise reject accessing it through the gp pointer. There are some 1190b57cec5SDimitry Andric // historic cases which GCC doesn't appear to respect any more. These 1200b57cec5SDimitry Andric // are .lit4, .lit8 and .srdata. For the moment reject these as well. 1210b57cec5SDimitry Andric return false; 1220b57cec5SDimitry Andric } 1230b57cec5SDimitry Andric 1240b57cec5SDimitry Andric // Enforce -mlocal-sdata. 1250b57cec5SDimitry Andric if (!LocalSData && GVA->hasLocalLinkage()) 1260b57cec5SDimitry Andric return false; 1270b57cec5SDimitry Andric 1280b57cec5SDimitry Andric // Enforce -mextern-sdata. 1290b57cec5SDimitry Andric if (!ExternSData && ((GVA->hasExternalLinkage() && GVA->isDeclaration()) || 1300b57cec5SDimitry Andric GVA->hasCommonLinkage())) 1310b57cec5SDimitry Andric return false; 1320b57cec5SDimitry Andric 1330b57cec5SDimitry Andric // Enforce -membedded-data. 1340b57cec5SDimitry Andric if (EmbeddedData && GVA->isConstant()) 1350b57cec5SDimitry Andric return false; 1360b57cec5SDimitry Andric 1370b57cec5SDimitry Andric Type *Ty = GVA->getValueType(); 1380b57cec5SDimitry Andric 1390b57cec5SDimitry Andric // It is possible that the type of the global is unsized, i.e. a declaration 1400b57cec5SDimitry Andric // of a extern struct. In this case don't presume it is in the small data 1410b57cec5SDimitry Andric // section. This happens e.g. when building the FreeBSD kernel. 1420b57cec5SDimitry Andric if (!Ty->isSized()) 1430b57cec5SDimitry Andric return false; 1440b57cec5SDimitry Andric 1450b57cec5SDimitry Andric return IsInSmallSection( 146*0fca6ea1SDimitry Andric GVA->getDataLayout().getTypeAllocSize(Ty)); 1470b57cec5SDimitry Andric } 1480b57cec5SDimitry Andric 1490b57cec5SDimitry Andric MCSection *MipsTargetObjectFile::SelectSectionForGlobal( 1500b57cec5SDimitry Andric const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { 1510b57cec5SDimitry Andric // TODO: Could also support "weak" symbols as well with ".gnu.linkonce.s.*" 1520b57cec5SDimitry Andric // sections? 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric // Handle Small Section classification here. 1550b57cec5SDimitry Andric if (Kind.isBSS() && IsGlobalInSmallSection(GO, TM, Kind)) 1560b57cec5SDimitry Andric return SmallBSSSection; 1570b57cec5SDimitry Andric if (Kind.isData() && IsGlobalInSmallSection(GO, TM, Kind)) 1580b57cec5SDimitry Andric return SmallDataSection; 1590b57cec5SDimitry Andric if (Kind.isReadOnly() && IsGlobalInSmallSection(GO, TM, Kind)) 1600b57cec5SDimitry Andric return SmallDataSection; 1610b57cec5SDimitry Andric 1620b57cec5SDimitry Andric // Otherwise, we work the same as ELF. 1630b57cec5SDimitry Andric return TargetLoweringObjectFileELF::SelectSectionForGlobal(GO, Kind, TM); 1640b57cec5SDimitry Andric } 1650b57cec5SDimitry Andric 1660b57cec5SDimitry Andric /// Return true if this constant should be placed into small data section. 1670b57cec5SDimitry Andric bool MipsTargetObjectFile::IsConstantInSmallSection( 1680b57cec5SDimitry Andric const DataLayout &DL, const Constant *CN, const TargetMachine &TM) const { 1690b57cec5SDimitry Andric return (static_cast<const MipsTargetMachine &>(TM) 1700b57cec5SDimitry Andric .getSubtargetImpl() 1710b57cec5SDimitry Andric ->useSmallSection() && 1720b57cec5SDimitry Andric LocalSData && IsInSmallSection(DL.getTypeAllocSize(CN->getType()))); 1730b57cec5SDimitry Andric } 1740b57cec5SDimitry Andric 1750b57cec5SDimitry Andric /// Return true if this constant should be placed into small data section. 1760b57cec5SDimitry Andric MCSection *MipsTargetObjectFile::getSectionForConstant(const DataLayout &DL, 1770b57cec5SDimitry Andric SectionKind Kind, 1780b57cec5SDimitry Andric const Constant *C, 1795ffd83dbSDimitry Andric Align &Alignment) const { 1800b57cec5SDimitry Andric if (IsConstantInSmallSection(DL, C, *TM)) 1810b57cec5SDimitry Andric return SmallDataSection; 1820b57cec5SDimitry Andric 1830b57cec5SDimitry Andric // Otherwise, we work the same as ELF. 1845ffd83dbSDimitry Andric return TargetLoweringObjectFileELF::getSectionForConstant(DL, Kind, C, 1855ffd83dbSDimitry Andric Alignment); 1860b57cec5SDimitry Andric } 1870b57cec5SDimitry Andric 1880b57cec5SDimitry Andric const MCExpr * 1890b57cec5SDimitry Andric MipsTargetObjectFile::getDebugThreadLocalSymbol(const MCSymbol *Sym) const { 1900b57cec5SDimitry Andric const MCExpr *Expr = 1910b57cec5SDimitry Andric MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); 1920b57cec5SDimitry Andric Expr = MCBinaryExpr::createAdd( 1930b57cec5SDimitry Andric Expr, MCConstantExpr::create(0x8000, getContext()), getContext()); 1940b57cec5SDimitry Andric return MipsMCExpr::create(MipsMCExpr::MEK_DTPREL, Expr, getContext()); 1950b57cec5SDimitry Andric } 196