brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.3 KiB · 78a9f3b Raw
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