brintos

brintos / llvm-project-archived public Read only

0
0
Text · 19.3 KiB · 8d6f7bf Raw
589 lines · cpp
1//===- lib/MC/MCELFStreamer.cpp - ELF Object Output -----------------------===//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// This file assembles .s files and emits ELF .o object files.10//11//===----------------------------------------------------------------------===//12 13#include "llvm/MC/MCELFStreamer.h"14#include "llvm/ADT/SmallVector.h"15#include "llvm/BinaryFormat/ELF.h"16#include "llvm/MC/MCAsmBackend.h"17#include "llvm/MC/MCAsmInfo.h"18#include "llvm/MC/MCAssembler.h"19#include "llvm/MC/MCCodeEmitter.h"20#include "llvm/MC/MCContext.h"21#include "llvm/MC/MCELFObjectWriter.h"22#include "llvm/MC/MCExpr.h"23#include "llvm/MC/MCFixup.h"24#include "llvm/MC/MCObjectFileInfo.h"25#include "llvm/MC/MCObjectWriter.h"26#include "llvm/MC/MCSection.h"27#include "llvm/MC/MCSectionELF.h"28#include "llvm/MC/MCStreamer.h"29#include "llvm/MC/MCSymbol.h"30#include "llvm/MC/MCSymbolELF.h"31#include "llvm/MC/TargetRegistry.h"32#include "llvm/Support/ErrorHandling.h"33#include "llvm/Support/LEB128.h"34#include <cassert>35#include <cstdint>36 37using namespace llvm;38 39MCELFStreamer::MCELFStreamer(MCContext &Context,40                             std::unique_ptr<MCAsmBackend> TAB,41                             std::unique_ptr<MCObjectWriter> OW,42                             std::unique_ptr<MCCodeEmitter> Emitter)43    : MCObjectStreamer(Context, std::move(TAB), std::move(OW),44                       std::move(Emitter)) {}45 46ELFObjectWriter &MCELFStreamer::getWriter() {47  return static_cast<ELFObjectWriter &>(getAssembler().getWriter());48}49 50void MCELFStreamer::initSections(bool NoExecStack, const MCSubtargetInfo &STI) {51  MCContext &Ctx = getContext();52  switchSection(Ctx.getObjectFileInfo()->getTextSection());53  emitCodeAlignment(Align(Ctx.getObjectFileInfo()->getTextSectionAlignment()),54                    &STI);55 56  if (NoExecStack)57    switchSection(Ctx.getAsmInfo()->getStackSection(Ctx, /*Exec=*/false));58}59 60void MCELFStreamer::emitLabel(MCSymbol *S, SMLoc Loc) {61  auto *Symbol = static_cast<MCSymbolELF *>(S);62  MCObjectStreamer::emitLabel(Symbol, Loc);63 64  const MCSectionELF &Section =65      static_cast<const MCSectionELF &>(*getCurrentSectionOnly());66  if (Section.getFlags() & ELF::SHF_TLS)67    Symbol->setType(ELF::STT_TLS);68}69 70void MCELFStreamer::emitLabelAtPos(MCSymbol *S, SMLoc Loc, MCFragment &F,71                                   uint64_t Offset) {72  auto *Symbol = static_cast<MCSymbolELF *>(S);73  MCObjectStreamer::emitLabelAtPos(Symbol, Loc, F, Offset);74 75  const MCSectionELF &Section =76      static_cast<const MCSectionELF &>(*getCurrentSectionOnly());77  if (Section.getFlags() & ELF::SHF_TLS)78    Symbol->setType(ELF::STT_TLS);79}80 81void MCELFStreamer::changeSection(MCSection *Section, uint32_t Subsection) {82  MCAssembler &Asm = getAssembler();83  auto *SectionELF = static_cast<const MCSectionELF *>(Section);84  const MCSymbol *Grp = SectionELF->getGroup();85  if (Grp)86    Asm.registerSymbol(*Grp);87  if (SectionELF->getFlags() & ELF::SHF_GNU_RETAIN)88    getWriter().markGnuAbi();89 90  MCObjectStreamer::changeSection(Section, Subsection);91  auto *Sym = static_cast<MCSymbolELF *>(Section->getBeginSymbol());92  Sym->setBinding(ELF::STB_LOCAL);93  Sym->setType(ELF::STT_SECTION);94}95 96void MCELFStreamer::emitWeakReference(MCSymbol *Alias, const MCSymbol *Target) {97  auto *A = static_cast<MCSymbolELF *>(Alias);98  if (A->isDefined()) {99    getContext().reportError(getStartTokLoc(), "symbol '" + A->getName() +100                                                   "' is already defined");101    return;102  }103  A->setVariableValue(MCSymbolRefExpr::create(Target, getContext()));104  A->setIsWeakref();105  getWriter().Weakrefs.push_back(A);106}107 108// When GNU as encounters more than one .type declaration for an object it seems109// to use a mechanism similar to the one below to decide which type is actually110// used in the object file.  The greater of T1 and T2 is selected based on the111// following ordering:112//  STT_NOTYPE < STT_OBJECT < STT_FUNC < STT_GNU_IFUNC < STT_TLS < anything else113// If neither T1 < T2 nor T2 < T1 according to this ordering, use T2 (the user114// provided type).115static unsigned CombineSymbolTypes(unsigned T1, unsigned T2) {116  for (unsigned Type : {ELF::STT_NOTYPE, ELF::STT_OBJECT, ELF::STT_FUNC,117                        ELF::STT_GNU_IFUNC, ELF::STT_TLS}) {118    if (T1 == Type)119      return T2;120    if (T2 == Type)121      return T1;122  }123 124  return T2;125}126 127bool MCELFStreamer::emitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) {128  auto *Symbol = static_cast<MCSymbolELF *>(S);129 130  // Adding a symbol attribute always introduces the symbol, note that an131  // important side effect of calling registerSymbol here is to register132  // the symbol with the assembler.133  getAssembler().registerSymbol(*Symbol);134 135  // The implementation of symbol attributes is designed to match 'as', but it136  // leaves much to desired. It doesn't really make sense to arbitrarily add and137  // remove flags, but 'as' allows this (in particular, see .desc).138  //139  // In the future it might be worth trying to make these operations more well140  // defined.141  switch (Attribute) {142  case MCSA_Cold:143  case MCSA_Extern:144  case MCSA_LazyReference:145  case MCSA_Reference:146  case MCSA_SymbolResolver:147  case MCSA_PrivateExtern:148  case MCSA_WeakDefinition:149  case MCSA_WeakDefAutoPrivate:150  case MCSA_Invalid:151  case MCSA_IndirectSymbol:152  case MCSA_Exported:153  case MCSA_WeakAntiDep:154    return false;155 156  case MCSA_NoDeadStrip:157    // Ignore for now.158    break;159 160  case MCSA_ELF_TypeGnuUniqueObject:161    Symbol->setType(CombineSymbolTypes(Symbol->getType(), ELF::STT_OBJECT));162    Symbol->setBinding(ELF::STB_GNU_UNIQUE);163    getWriter().markGnuAbi();164    break;165 166  case MCSA_Global:167    // For `.weak x; .global x`, GNU as sets the binding to STB_WEAK while we168    // traditionally set the binding to STB_GLOBAL. This is error-prone, so we169    // error on such cases. Note, we also disallow changed binding from .local.170    if (Symbol->isBindingSet() && Symbol->getBinding() != ELF::STB_GLOBAL)171      getContext().reportError(getStartTokLoc(),172                               Symbol->getName() +173                                   " changed binding to STB_GLOBAL");174    Symbol->setBinding(ELF::STB_GLOBAL);175    break;176 177  case MCSA_WeakReference:178  case MCSA_Weak:179    // For `.global x; .weak x`, both MC and GNU as set the binding to STB_WEAK.180    // We emit a warning for now but may switch to an error in the future.181    if (Symbol->isBindingSet() && Symbol->getBinding() != ELF::STB_WEAK)182      getContext().reportWarning(183          getStartTokLoc(), Symbol->getName() + " changed binding to STB_WEAK");184    Symbol->setBinding(ELF::STB_WEAK);185    break;186 187  case MCSA_Local:188    if (Symbol->isBindingSet() && Symbol->getBinding() != ELF::STB_LOCAL)189      getContext().reportError(getStartTokLoc(),190                               Symbol->getName() +191                                   " changed binding to STB_LOCAL");192    Symbol->setBinding(ELF::STB_LOCAL);193    break;194 195  case MCSA_ELF_TypeFunction:196    Symbol->setType(CombineSymbolTypes(Symbol->getType(), ELF::STT_FUNC));197    break;198 199  case MCSA_ELF_TypeIndFunction:200    Symbol->setType(CombineSymbolTypes(Symbol->getType(), ELF::STT_GNU_IFUNC));201    getWriter().markGnuAbi();202    break;203 204  case MCSA_ELF_TypeObject:205    Symbol->setType(CombineSymbolTypes(Symbol->getType(), ELF::STT_OBJECT));206    break;207 208  case MCSA_ELF_TypeTLS:209    Symbol->setType(CombineSymbolTypes(Symbol->getType(), ELF::STT_TLS));210    break;211 212  case MCSA_ELF_TypeCommon:213    // TODO: Emit these as a common symbol.214    Symbol->setType(CombineSymbolTypes(Symbol->getType(), ELF::STT_OBJECT));215    break;216 217  case MCSA_ELF_TypeNoType:218    Symbol->setType(CombineSymbolTypes(Symbol->getType(), ELF::STT_NOTYPE));219    break;220 221  case MCSA_Protected:222    Symbol->setVisibility(ELF::STV_PROTECTED);223    break;224 225  case MCSA_Memtag:226    Symbol->setMemtag(true);227    break;228 229  case MCSA_Hidden:230    Symbol->setVisibility(ELF::STV_HIDDEN);231    break;232 233  case MCSA_Internal:234    Symbol->setVisibility(ELF::STV_INTERNAL);235    break;236 237  case MCSA_AltEntry:238    llvm_unreachable("ELF doesn't support the .alt_entry attribute");239 240  case MCSA_LGlobal:241    llvm_unreachable("ELF doesn't support the .lglobl attribute");242  }243 244  return true;245}246 247void MCELFStreamer::emitCommonSymbol(MCSymbol *S, uint64_t Size,248                                     Align ByteAlignment) {249  auto *Symbol = static_cast<MCSymbolELF *>(S);250  getAssembler().registerSymbol(*Symbol);251 252  if (!Symbol->isBindingSet())253    Symbol->setBinding(ELF::STB_GLOBAL);254 255  Symbol->setType(ELF::STT_OBJECT);256 257  if (Symbol->getBinding() == ELF::STB_LOCAL) {258    MCSection &Section = *getAssembler().getContext().getELFSection(259        ".bss", ELF::SHT_NOBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC);260    MCSectionSubPair P = getCurrentSection();261    switchSection(&Section);262 263    emitValueToAlignment(ByteAlignment, 0, 1, 0);264    emitLabel(Symbol);265    emitZeros(Size);266 267    switchSection(P.first, P.second);268  } else {269    if (Symbol->declareCommon(Size, ByteAlignment))270      report_fatal_error(Twine("Symbol: ") + Symbol->getName() +271                         " redeclared as different type");272  }273 274  Symbol->setSize(MCConstantExpr::create(Size, getContext()));275}276 277void MCELFStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) {278  static_cast<MCSymbolELF *>(Symbol)->setSize(Value);279}280 281void MCELFStreamer::emitELFSymverDirective(const MCSymbol *OriginalSym,282                                           StringRef Name,283                                           bool KeepOriginalSym) {284  getWriter().Symvers.push_back(ELFObjectWriter::Symver{285      getStartTokLoc(), OriginalSym, Name, KeepOriginalSym});286}287 288void MCELFStreamer::emitLocalCommonSymbol(MCSymbol *S, uint64_t Size,289                                          Align ByteAlignment) {290  auto *Symbol = static_cast<MCSymbolELF *>(S);291  // FIXME: Should this be caught and done earlier?292  getAssembler().registerSymbol(*Symbol);293  Symbol->setBinding(ELF::STB_LOCAL);294  emitCommonSymbol(Symbol, Size, ByteAlignment);295}296 297void MCELFStreamer::emitCGProfileEntry(const MCSymbolRefExpr *From,298                                       const MCSymbolRefExpr *To,299                                       uint64_t Count) {300  getWriter().getCGProfile().push_back({From, To, Count});301}302 303void MCELFStreamer::emitIdent(StringRef IdentString) {304  MCSection *Comment = getAssembler().getContext().getELFSection(305      ".comment", ELF::SHT_PROGBITS, ELF::SHF_MERGE | ELF::SHF_STRINGS, 1);306  pushSection();307  switchSection(Comment);308  if (!SeenIdent) {309    emitInt8(0);310    SeenIdent = true;311  }312  emitBytes(IdentString);313  emitInt8(0);314  popSection();315}316 317void MCELFStreamer::finalizeCGProfileEntry(const MCSymbolRefExpr *Sym,318                                           uint64_t Offset,319                                           const MCSymbolRefExpr *&SRE) {320  const MCSymbol *S = &SRE->getSymbol();321  if (S->isTemporary()) {322    if (!S->isInSection()) {323      getContext().reportError(324          SRE->getLoc(), Twine("Reference to undefined temporary symbol ") +325                             "`" + S->getName() + "`");326      return;327    }328    S = S->getSection().getBeginSymbol();329    S->setUsedInReloc();330    SRE = MCSymbolRefExpr::create(S, getContext(), SRE->getLoc());331  }332  auto *O = MCBinaryExpr::createAdd(333      Sym, MCConstantExpr::create(Offset, getContext()), getContext());334  MCObjectStreamer::emitRelocDirective(*O, "BFD_RELOC_NONE", SRE);335}336 337void MCELFStreamer::finalizeCGProfile() {338  ELFObjectWriter &W = getWriter();339  if (W.getCGProfile().empty())340    return;341  MCSection *CGProfile = getAssembler().getContext().getELFSection(342      ".llvm.call-graph-profile", ELF::SHT_LLVM_CALL_GRAPH_PROFILE,343      ELF::SHF_EXCLUDE, /*sizeof(Elf_CGProfile_Impl<>)=*/8);344  pushSection();345  switchSection(CGProfile);346  uint64_t Offset = 0;347  auto *Sym =348      MCSymbolRefExpr::create(CGProfile->getBeginSymbol(), getContext());349  for (auto &E : W.getCGProfile()) {350    finalizeCGProfileEntry(Sym, Offset, E.From);351    finalizeCGProfileEntry(Sym, Offset, E.To);352    emitIntValue(E.Count, sizeof(uint64_t));353    Offset += sizeof(uint64_t);354  }355  popSection();356}357 358void MCELFStreamer::finishImpl() {359  // Emit the .gnu attributes section if any attributes have been added.360  if (!GNUAttributes.empty()) {361    MCSection *DummyAttributeSection = nullptr;362    createAttributesSection("gnu", ".gnu.attributes", ELF::SHT_GNU_ATTRIBUTES,363                            DummyAttributeSection, GNUAttributes);364  }365 366  finalizeCGProfile();367  emitFrames();368 369  this->MCObjectStreamer::finishImpl();370}371 372void MCELFStreamer::setAttributeItem(unsigned Attribute, unsigned Value,373                                     bool OverwriteExisting) {374  // Look for existing attribute item375  if (AttributeItem *Item = getAttributeItem(Attribute)) {376    if (!OverwriteExisting)377      return;378    Item->Type = AttributeItem::NumericAttribute;379    Item->IntValue = Value;380    return;381  }382 383  // Create new attribute item384  AttributeItem Item = {AttributeItem::NumericAttribute, Attribute, Value,385                        std::string(StringRef(""))};386  Contents.push_back(Item);387}388 389void MCELFStreamer::setAttributeItem(unsigned Attribute, StringRef Value,390                                     bool OverwriteExisting) {391  // Look for existing attribute item392  if (AttributeItem *Item = getAttributeItem(Attribute)) {393    if (!OverwriteExisting)394      return;395    Item->Type = AttributeItem::TextAttribute;396    Item->StringValue = std::string(Value);397    return;398  }399 400  // Create new attribute item401  AttributeItem Item = {AttributeItem::TextAttribute, Attribute, 0,402                        std::string(Value)};403  Contents.push_back(Item);404}405 406void MCELFStreamer::setAttributeItems(unsigned Attribute, unsigned IntValue,407                                      StringRef StringValue,408                                      bool OverwriteExisting) {409  // Look for existing attribute item410  if (AttributeItem *Item = getAttributeItem(Attribute)) {411    if (!OverwriteExisting)412      return;413    Item->Type = AttributeItem::NumericAndTextAttributes;414    Item->IntValue = IntValue;415    Item->StringValue = std::string(StringValue);416    return;417  }418 419  // Create new attribute item420  AttributeItem Item = {AttributeItem::NumericAndTextAttributes, Attribute,421                        IntValue, std::string(StringValue)};422  Contents.push_back(Item);423}424 425MCELFStreamer::AttributeItem *426MCELFStreamer::getAttributeItem(unsigned Attribute) {427  for (AttributeItem &Item : Contents)428    if (Item.Tag == Attribute)429      return &Item;430  return nullptr;431}432 433size_t MCELFStreamer::calculateContentSize(434    SmallVector<AttributeItem, 64> &AttrsVec) const {435  size_t Result = 0;436  for (const AttributeItem &Item : AttrsVec) {437    switch (Item.Type) {438    case AttributeItem::HiddenAttribute:439      break;440    case AttributeItem::NumericAttribute:441      Result += getULEB128Size(Item.Tag);442      Result += getULEB128Size(Item.IntValue);443      break;444    case AttributeItem::TextAttribute:445      Result += getULEB128Size(Item.Tag);446      Result += Item.StringValue.size() + 1; // string + '\0'447      break;448    case AttributeItem::NumericAndTextAttributes:449      Result += getULEB128Size(Item.Tag);450      Result += getULEB128Size(Item.IntValue);451      Result += Item.StringValue.size() + 1; // string + '\0';452      break;453    }454  }455  return Result;456}457 458void MCELFStreamer::createAttributesSection(459    StringRef Vendor, const Twine &Section, unsigned Type,460    MCSection *&AttributeSection, SmallVector<AttributeItem, 64> &AttrsVec) {461  // <format-version>462  // [ <section-length> "vendor-name"463  // [ <file-tag> <size> <attribute>*464  //   | <section-tag> <size> <section-number>* 0 <attribute>*465  //   | <symbol-tag> <size> <symbol-number>* 0 <attribute>*466  //   ]+467  // ]*468 469  // Switch section to AttributeSection or get/create the section.470  if (AttributeSection) {471    switchSection(AttributeSection);472  } else {473    AttributeSection = getContext().getELFSection(Section, Type, 0);474    switchSection(AttributeSection);475 476    // Format version477    emitInt8(0x41);478  }479 480  // Vendor size + Vendor name + '\0'481  const size_t VendorHeaderSize = 4 + Vendor.size() + 1;482 483  // Tag + Tag Size484  const size_t TagHeaderSize = 1 + 4;485 486  const size_t ContentsSize = calculateContentSize(AttrsVec);487 488  emitInt32(VendorHeaderSize + TagHeaderSize + ContentsSize);489  emitBytes(Vendor);490  emitInt8(0); // '\0'491 492  emitInt8(ARMBuildAttrs::File);493  emitInt32(TagHeaderSize + ContentsSize);494 495  // Size should have been accounted for already, now496  // emit each field as its type (ULEB or String)497  for (const AttributeItem &Item : AttrsVec) {498    emitULEB128IntValue(Item.Tag);499    switch (Item.Type) {500    default:501      llvm_unreachable("Invalid attribute type");502    case AttributeItem::NumericAttribute:503      emitULEB128IntValue(Item.IntValue);504      break;505    case AttributeItem::TextAttribute:506      emitBytes(Item.StringValue);507      emitInt8(0); // '\0'508      break;509    case AttributeItem::NumericAndTextAttributes:510      emitULEB128IntValue(Item.IntValue);511      emitBytes(Item.StringValue);512      emitInt8(0); // '\0'513      break;514    }515  }516 517  AttrsVec.clear();518}519 520void MCELFStreamer::createAttributesWithSubsection(521    MCSection *&AttributeSection, const Twine &Section, unsigned Type,522    SmallVector<AttributeSubSection, 64> &SubSectionVec) {523  // <format-version: 'A'>524  // [ <uint32: subsection-length> NTBS: vendor-name525  //   <bytes: vendor-data>526  // ]*527  // vendor-data expends to:528  // <uint8: optional> <uint8: parameter type> <attribute>*529  if (0 == SubSectionVec.size()) {530    return;531  }532 533  // Switch section to AttributeSection or get/create the section.534  if (AttributeSection) {535    switchSection(AttributeSection);536  } else {537    AttributeSection = getContext().getELFSection(Section, Type, 0);538    switchSection(AttributeSection);539 540    // Format version541    emitInt8(0x41);542  }543 544  for (AttributeSubSection &SubSection : SubSectionVec) {545    // subsection-length + vendor-name + '\0'546    const size_t VendorHeaderSize = 4 + SubSection.VendorName.size() + 1;547    // optional + parameter-type548    const size_t VendorParameters = 1 + 1;549    const size_t ContentsSize = calculateContentSize(SubSection.Content);550 551    emitInt32(VendorHeaderSize + VendorParameters + ContentsSize);552    emitBytes(SubSection.VendorName);553    emitInt8(0); // '\0'554    emitInt8(SubSection.IsOptional);555    emitInt8(SubSection.ParameterType);556 557    for (AttributeItem &Item : SubSection.Content) {558      emitULEB128IntValue(Item.Tag);559      switch (Item.Type) {560      default:561        assert(0 && "Invalid attribute type");562        break;563      case AttributeItem::NumericAttribute:564        emitULEB128IntValue(Item.IntValue);565        break;566      case AttributeItem::TextAttribute:567        emitBytes(Item.StringValue);568        emitInt8(0); // '\0'569        break;570      case AttributeItem::NumericAndTextAttributes:571        emitULEB128IntValue(Item.IntValue);572        emitBytes(Item.StringValue);573        emitInt8(0); // '\0'574        break;575      }576    }577  }578  SubSectionVec.clear();579}580 581MCStreamer *llvm::createELFStreamer(MCContext &Context,582                                    std::unique_ptr<MCAsmBackend> &&MAB,583                                    std::unique_ptr<MCObjectWriter> &&OW,584                                    std::unique_ptr<MCCodeEmitter> &&CE) {585  MCELFStreamer *S =586      new MCELFStreamer(Context, std::move(MAB), std::move(OW), std::move(CE));587  return S;588}589