194 lines · cpp
1//===-- MipsTargetObjectFile.cpp - Mips Object Files ----------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "MipsTargetObjectFile.h"10#include "MCTargetDesc/MipsMCAsmInfo.h"11#include "MipsSubtarget.h"12#include "MipsTargetMachine.h"13#include "llvm/BinaryFormat/ELF.h"14#include "llvm/IR/DataLayout.h"15#include "llvm/IR/GlobalVariable.h"16#include "llvm/MC/MCContext.h"17#include "llvm/MC/MCSectionELF.h"18#include "llvm/Support/CommandLine.h"19#include "llvm/Target/TargetMachine.h"20using namespace llvm;21 22static cl::opt<unsigned>23SSThreshold("mips-ssection-threshold", cl::Hidden,24 cl::desc("Small data and bss section threshold size (default=8)"),25 cl::init(8));26 27static cl::opt<bool>28LocalSData("mlocal-sdata", cl::Hidden,29 cl::desc("MIPS: Use gp_rel for object-local data."),30 cl::init(true));31 32static cl::opt<bool>33ExternSData("mextern-sdata", cl::Hidden,34 cl::desc("MIPS: Use gp_rel for data that is not defined by the "35 "current object."),36 cl::init(true));37 38static cl::opt<bool>39EmbeddedData("membedded-data", cl::Hidden,40 cl::desc("MIPS: Try to allocate variables in the following"41 " sections if possible: .rodata, .sdata, .data ."),42 cl::init(false));43 44void MipsTargetObjectFile::Initialize(MCContext &Ctx, const TargetMachine &TM){45 TargetLoweringObjectFileELF::Initialize(Ctx, TM);46 47 SmallDataSection = getContext().getELFSection(48 ".sdata", ELF::SHT_PROGBITS,49 ELF::SHF_WRITE | ELF::SHF_ALLOC | ELF::SHF_MIPS_GPREL);50 51 SmallBSSSection = getContext().getELFSection(".sbss", ELF::SHT_NOBITS,52 ELF::SHF_WRITE | ELF::SHF_ALLOC |53 ELF::SHF_MIPS_GPREL);54 this->TM = &static_cast<const MipsTargetMachine &>(TM);55}56 57// A address must be loaded from a small section if its size is less than the58// small section size threshold. Data in this section must be addressed using59// gp_rel operator.60static bool IsInSmallSection(uint64_t Size) {61 // gcc has traditionally not treated zero-sized objects as small data, so this62 // is effectively part of the ABI.63 return Size > 0 && Size <= SSThreshold;64}65 66/// Return true if this global address should be placed into small data/bss67/// section.68bool MipsTargetObjectFile::IsGlobalInSmallSection(69 const GlobalObject *GO, const TargetMachine &TM) const {70 // We first check the case where global is a declaration, because finding71 // section kind using getKindForGlobal() is only allowed for global72 // definitions.73 if (GO->isDeclaration() || GO->hasAvailableExternallyLinkage())74 return IsGlobalInSmallSectionImpl(GO, TM);75 76 return IsGlobalInSmallSection(GO, TM, getKindForGlobal(GO, TM));77}78 79/// Return true if this global address should be placed into small data/bss80/// section.81bool MipsTargetObjectFile::82IsGlobalInSmallSection(const GlobalObject *GO, const TargetMachine &TM,83 SectionKind Kind) const {84 return IsGlobalInSmallSectionImpl(GO, TM) &&85 (Kind.isData() || Kind.isBSS() || Kind.isCommon() ||86 Kind.isReadOnly());87}88 89/// Return true if this global address should be placed into small data/bss90/// section. This method does all the work, except for checking the section91/// kind.92bool MipsTargetObjectFile::93IsGlobalInSmallSectionImpl(const GlobalObject *GO,94 const TargetMachine &TM) const {95 const MipsSubtarget &Subtarget =96 *static_cast<const MipsTargetMachine &>(TM).getSubtargetImpl();97 98 // Return if small section is not available.99 if (!Subtarget.useSmallSection())100 return false;101 102 // Only global variables, not functions.103 const GlobalVariable *GVA = dyn_cast<GlobalVariable>(GO);104 if (!GVA)105 return false;106 107 // If the variable has an explicit section, it is placed in that section but108 // it's addressing mode may change.109 if (GVA->hasSection()) {110 StringRef Section = GVA->getSection();111 112 // Explicitly placing any variable in the small data section overrides113 // the global -G value.114 if (Section == ".sdata" || Section == ".sbss")115 return true;116 117 // Otherwise reject accessing it through the gp pointer. There are some118 // historic cases which GCC doesn't appear to respect any more. These119 // are .lit4, .lit8 and .srdata. For the moment reject these as well.120 return false;121 }122 123 // Enforce -mlocal-sdata.124 if (!LocalSData && GVA->hasLocalLinkage())125 return false;126 127 // Enforce -mextern-sdata.128 if (!ExternSData && ((GVA->hasExternalLinkage() && GVA->isDeclaration()) ||129 GVA->hasCommonLinkage()))130 return false;131 132 // Enforce -membedded-data.133 if (EmbeddedData && GVA->isConstant())134 return false;135 136 Type *Ty = GVA->getValueType();137 138 // It is possible that the type of the global is unsized, i.e. a declaration139 // of a extern struct. In this case don't presume it is in the small data140 // section. This happens e.g. when building the FreeBSD kernel.141 if (!Ty->isSized())142 return false;143 144 return IsInSmallSection(145 GVA->getDataLayout().getTypeAllocSize(Ty));146}147 148MCSection *MipsTargetObjectFile::SelectSectionForGlobal(149 const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {150 // TODO: Could also support "weak" symbols as well with ".gnu.linkonce.s.*"151 // sections?152 153 // Handle Small Section classification here.154 if (Kind.isBSS() && IsGlobalInSmallSection(GO, TM, Kind))155 return SmallBSSSection;156 if (Kind.isData() && IsGlobalInSmallSection(GO, TM, Kind))157 return SmallDataSection;158 if (Kind.isReadOnly() && IsGlobalInSmallSection(GO, TM, Kind))159 return SmallDataSection;160 161 // Otherwise, we work the same as ELF.162 return TargetLoweringObjectFileELF::SelectSectionForGlobal(GO, Kind, TM);163}164 165/// Return true if this constant should be placed into small data section.166bool MipsTargetObjectFile::IsConstantInSmallSection(167 const DataLayout &DL, const Constant *CN, const TargetMachine &TM) const {168 return (static_cast<const MipsTargetMachine &>(TM)169 .getSubtargetImpl()170 ->useSmallSection() &&171 LocalSData && IsInSmallSection(DL.getTypeAllocSize(CN->getType())));172}173 174/// Return true if this constant should be placed into small data section.175MCSection *MipsTargetObjectFile::getSectionForConstant(const DataLayout &DL,176 SectionKind Kind,177 const Constant *C,178 Align &Alignment) const {179 if (IsConstantInSmallSection(DL, C, *TM))180 return SmallDataSection;181 182 // Otherwise, we work the same as ELF.183 return TargetLoweringObjectFileELF::getSectionForConstant(DL, Kind, C,184 Alignment);185}186 187const MCExpr *188MipsTargetObjectFile::getDebugThreadLocalSymbol(const MCSymbol *Sym) const {189 const MCExpr *Expr = MCSymbolRefExpr::create(Sym, getContext());190 Expr = MCBinaryExpr::createAdd(191 Expr, MCConstantExpr::create(0x8000, getContext()), getContext());192 return MCSpecifierExpr::create(Expr, Mips::S_DTPREL, getContext());193}194