brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.1 KiB · d5afc8b Raw
229 lines · cpp
1//===- lib/MC/MCWasmStreamer.cpp - Wasm 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 Wasm .o object files.10//11//===----------------------------------------------------------------------===//12 13#include "llvm/MC/MCWasmStreamer.h"14#include "llvm/MC/MCAsmBackend.h"15#include "llvm/MC/MCAssembler.h"16#include "llvm/MC/MCCodeEmitter.h"17#include "llvm/MC/MCContext.h"18#include "llvm/MC/MCExpr.h"19#include "llvm/MC/MCFixup.h"20#include "llvm/MC/MCObjectStreamer.h"21#include "llvm/MC/MCSection.h"22#include "llvm/MC/MCSectionWasm.h"23#include "llvm/MC/MCSymbol.h"24#include "llvm/MC/MCSymbolWasm.h"25#include "llvm/MC/SectionKind.h"26#include "llvm/MC/TargetRegistry.h"27#include "llvm/Support/Alignment.h"28#include "llvm/Support/ErrorHandling.h"29#include "llvm/Support/MathExtras.h"30 31namespace llvm {32class MCContext;33class MCStreamer;34class MCSubtargetInfo;35} // namespace llvm36 37using namespace llvm;38 39MCWasmStreamer::~MCWasmStreamer() = default; // anchor.40 41void MCWasmStreamer::emitLabel(MCSymbol *S, SMLoc Loc) {42  auto *Symbol = static_cast<MCSymbolWasm *>(S);43  MCObjectStreamer::emitLabel(Symbol, Loc);44 45  const MCSectionWasm &Section =46      static_cast<const MCSectionWasm &>(*getCurrentSectionOnly());47  if (Section.getSegmentFlags() & wasm::WASM_SEG_FLAG_TLS)48    Symbol->setTLS();49}50 51void MCWasmStreamer::emitLabelAtPos(MCSymbol *S, SMLoc Loc, MCFragment &F,52                                    uint64_t Offset) {53  auto *Symbol = static_cast<MCSymbolWasm *>(S);54  MCObjectStreamer::emitLabelAtPos(Symbol, Loc, F, Offset);55 56  const MCSectionWasm &Section =57      static_cast<const MCSectionWasm &>(*getCurrentSectionOnly());58  if (Section.getSegmentFlags() & wasm::WASM_SEG_FLAG_TLS)59    Symbol->setTLS();60}61 62void MCWasmStreamer::emitAssignment(MCSymbol *S, const MCExpr *Value) {63  auto *Symbol = static_cast<MCSymbolWasm *>(S);64 65  // wasm has no absolute addressing. A symbol assigned a bare integer constant66  // ("sym = N" / ".set sym, N", with no symbol reference) cannot be modeled as67  // an absolute symbol: WasmObjectWriter's alias pass calls getBaseSymbol(),68  // which is null for a pure constant, and previously aborted MC finalization69  // with "absolute addressing not supported". glibc emits exactly this for70  // address-taken linkage markers (e.g. _nl_current_LC_*_used from71  // _NL_CURRENT_DEFINE in locale/localeinfo.h), where the symbol's *address* is72  // taken to force a translation unit to be linked, and any read of the symbol73  // is expected to yield the constant.74  //75  // Lower a named (non-temporary) absolute-constant symbol to a real defined76  // data object that holds the constant in its own data section. It then has a77  // genuine wasm linear-memory address that can be taken and relocated at link78  // (resolving an undefined reference in another object), and a load of it79  // yields the constant. This mirrors what GNU-as effectively provides for the80  // construct on ELF (a defined symbol with an address). It is never-silent:81  // the address is real, the value is preserved, and nothing is dropped.82  //83  // Assignments that reference other symbols (true aliases, label differences)84  // are left to the normal assembler-alias machinery (the WasmObjectWriter85  // alias pass and the prior alias-to-undefined / .symver fixes). Temporary,86  // assembler-internal absolute constants are also left as plain assignments:87  // they are folded into immediates at encode time and never need an address.88  int64_t Const;89  if (!Symbol->isTemporary() && Value->evaluateAsAbsolute(Const)) {90    MCContext &Ctx = getContext();91 92    // Store the constant in the target pointer width, widened only if needed so93    // the stored bytes equal the constant exactly (no silent truncation).94    unsigned Width = Ctx.getTargetTriple().isArch64Bit() ? 8 : 4;95    while (Width < 8 && !isIntN(Width * 8, Const) &&96           !isUIntN(Width * 8, static_cast<uint64_t>(Const)))97      Width *= 2;98 99    // A dedicated data section so the marker is independently addressable and100    // garbage-collectable, exactly like any other defined data symbol.101    MCSection *DataSec = Ctx.getWasmSection(Twine(".data.") + Symbol->getName(),102                                            SectionKind::getData());103 104    MCSection *Prev = getCurrentSectionOnly();105    switchSection(DataSec);106    emitValueToAlignment(Align(Width));107    emitLabel(Symbol);108    emitIntValue(static_cast<uint64_t>(Const), Width);109    Symbol->setSize(MCConstantExpr::create(Width, Ctx));110    // Record the constant so a repeated, identical "sym = N" (which glibc emits111    // per-TU and llvm-link concatenates without dedup) is recognized in the112    // parser as an idempotent no-op rather than colliding as a redefinition of113    // this now-defined data label, while a repeat to a *different* constant is114    // still rejected loudly. See MCParserUtils::parseAssignmentExpression.115    Symbol->setAbsoluteConstant(Const);116    if (Prev)117      switchSection(Prev);118    return;119  }120 121  MCObjectStreamer::emitAssignment(S, Value);122}123 124void MCWasmStreamer::changeSection(MCSection *Section, uint32_t Subsection) {125  MCAssembler &Asm = getAssembler();126  auto *SectionWasm = static_cast<const MCSectionWasm *>(Section);127  const MCSymbol *Grp = SectionWasm->getGroup();128  if (Grp)129    Asm.registerSymbol(*Grp);130 131  this->MCObjectStreamer::changeSection(Section, Subsection);132  Asm.registerSymbol(*Section->getBeginSymbol());133}134 135bool MCWasmStreamer::emitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) {136  assert(Attribute != MCSA_IndirectSymbol && "indirect symbols not supported");137  auto *Symbol = static_cast<MCSymbolWasm *>(S);138 139  // Adding a symbol attribute always introduces the symbol; note that an140  // important side effect of calling registerSymbol here is to register the141  // symbol with the assembler.142  getAssembler().registerSymbol(*Symbol);143 144  switch (Attribute) {145  case MCSA_LazyReference:146  case MCSA_Reference:147  case MCSA_SymbolResolver:148  case MCSA_PrivateExtern:149  case MCSA_WeakDefinition:150  case MCSA_WeakDefAutoPrivate:151  case MCSA_Invalid:152  case MCSA_IndirectSymbol:153  case MCSA_Protected:154  case MCSA_Exported:155    return false;156 157  case MCSA_Hidden:158    Symbol->setHidden(true);159    break;160 161  case MCSA_Weak:162  case MCSA_WeakReference:163    Symbol->setWeak(true);164    Symbol->setExternal(true);165    break;166 167  case MCSA_Global:168    Symbol->setExternal(true);169    break;170 171  case MCSA_ELF_TypeFunction:172    Symbol->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);173    break;174 175  case MCSA_ELF_TypeTLS:176    Symbol->setTLS();177    break;178 179  case MCSA_ELF_TypeObject:180  case MCSA_Cold:181    break;182 183  case MCSA_NoDeadStrip:184    Symbol->setNoStrip();185    break;186 187  default:188    // unrecognized directive189    llvm_unreachable("unexpected MCSymbolAttr");190    return false;191  }192 193  return true;194}195 196void MCWasmStreamer::emitCommonSymbol(MCSymbol *S, uint64_t Size,197                                      Align ByteAlignment) {198  llvm_unreachable("Common symbols are not yet implemented for Wasm");199}200 201void MCWasmStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) {202  static_cast<MCSymbolWasm *>(Symbol)->setSize(Value);203}204 205void MCWasmStreamer::emitLocalCommonSymbol(MCSymbol *S, uint64_t Size,206                                           Align ByteAlignment) {207  llvm_unreachable("Local common symbols are not yet implemented for Wasm");208}209 210void MCWasmStreamer::emitIdent(StringRef IdentString) {211  // TODO(sbc): Add the ident section once we support mergable strings212  // sections in the object format213}214 215void MCWasmStreamer::finishImpl() {216  emitFrames();217 218  this->MCObjectStreamer::finishImpl();219}220 221MCStreamer *llvm::createWasmStreamer(MCContext &Context,222                                     std::unique_ptr<MCAsmBackend> &&MAB,223                                     std::unique_ptr<MCObjectWriter> &&OW,224                                     std::unique_ptr<MCCodeEmitter> &&CE) {225  MCWasmStreamer *S =226      new MCWasmStreamer(Context, std::move(MAB), std::move(OW), std::move(CE));227  return S;228}229