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