//===-- RISCVELFStreamer.cpp - RISC-V ELF Target Streamer Methods ---------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file provides RISC-V specific target streamer methods. // //===----------------------------------------------------------------------===// #include "RISCVELFStreamer.h" #include "RISCVAsmBackend.h" #include "RISCVBaseInfo.h" #include "RISCVMCTargetDesc.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCValue.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/RISCVAttributes.h" using namespace llvm; // This part is for ELF object output. RISCVTargetELFStreamer::RISCVTargetELFStreamer(MCStreamer &S, const MCSubtargetInfo &STI) : RISCVTargetStreamer(S), CurrentVendor("riscv") { MCAssembler &MCA = getStreamer().getAssembler(); const FeatureBitset &Features = STI.getFeatureBits(); auto &MAB = static_cast(MCA.getBackend()); setTargetABI(RISCVABI::computeTargetABI(STI.getTargetTriple(), Features, MAB.getTargetOptions().getABIName())); setFlagsFromFeatures(STI); // `j label` in `.option norelax; j label; .option relax; ...; label:` needs a // relocation to ensure the jump target is correct after linking. This is due // to a limitation that shouldForceRelocation has to make the decision upfront // without knowing a possibly future .option relax. When RISCVAsmParser is used, // its ParseInstruction may call setForceRelocs as well. if (STI.hasFeature(RISCV::FeatureRelax)) static_cast(MAB).setForceRelocs(); } RISCVELFStreamer &RISCVTargetELFStreamer::getStreamer() { return static_cast(Streamer); } void RISCVTargetELFStreamer::emitDirectiveOptionPush() {} void RISCVTargetELFStreamer::emitDirectiveOptionPop() {} void RISCVTargetELFStreamer::emitDirectiveOptionPIC() {} void RISCVTargetELFStreamer::emitDirectiveOptionNoPIC() {} void RISCVTargetELFStreamer::emitDirectiveOptionRVC() {} void RISCVTargetELFStreamer::emitDirectiveOptionNoRVC() {} void RISCVTargetELFStreamer::emitDirectiveOptionRelax() {} void RISCVTargetELFStreamer::emitDirectiveOptionNoRelax() {} void RISCVTargetELFStreamer::emitAttribute(unsigned Attribute, unsigned Value) { getStreamer().setAttributeItem(Attribute, Value, /*OverwriteExisting=*/true); } void RISCVTargetELFStreamer::emitTextAttribute(unsigned Attribute, StringRef String) { getStreamer().setAttributeItem(Attribute, String, /*OverwriteExisting=*/true); } void RISCVTargetELFStreamer::emitIntTextAttribute(unsigned Attribute, unsigned IntValue, StringRef StringValue) { getStreamer().setAttributeItems(Attribute, IntValue, StringValue, /*OverwriteExisting=*/true); } void RISCVTargetELFStreamer::finishAttributeSection() { RISCVELFStreamer &S = getStreamer(); if (S.Contents.empty()) return; S.emitAttributesSection(CurrentVendor, ".riscv.attributes", ELF::SHT_RISCV_ATTRIBUTES, AttributeSection); } void RISCVTargetELFStreamer::finish() { RISCVTargetStreamer::finish(); ELFObjectWriter &W = getStreamer().getWriter(); RISCVABI::ABI ABI = getTargetABI(); unsigned EFlags = W.getELFHeaderEFlags(); if (hasRVC()) EFlags |= ELF::EF_RISCV_RVC; if (hasTSO()) EFlags |= ELF::EF_RISCV_TSO; switch (ABI) { case RISCVABI::ABI_ILP32: case RISCVABI::ABI_LP64: break; case RISCVABI::ABI_ILP32F: case RISCVABI::ABI_LP64F: EFlags |= ELF::EF_RISCV_FLOAT_ABI_SINGLE; break; case RISCVABI::ABI_ILP32D: case RISCVABI::ABI_LP64D: EFlags |= ELF::EF_RISCV_FLOAT_ABI_DOUBLE; break; case RISCVABI::ABI_ILP32E: case RISCVABI::ABI_LP64E: EFlags |= ELF::EF_RISCV_RVE; break; case RISCVABI::ABI_Unknown: llvm_unreachable("Improperly initialised target ABI"); } W.setELFHeaderEFlags(EFlags); } void RISCVTargetELFStreamer::reset() { AttributeSection = nullptr; } void RISCVTargetELFStreamer::emitDirectiveVariantCC(MCSymbol &Symbol) { getStreamer().getAssembler().registerSymbol(Symbol); cast(Symbol).setOther(ELF::STO_RISCV_VARIANT_CC); } void RISCVELFStreamer::reset() { static_cast(getTargetStreamer())->reset(); MCELFStreamer::reset(); LastMappingSymbols.clear(); LastEMS = EMS_None; } void RISCVELFStreamer::emitDataMappingSymbol() { if (LastEMS == EMS_Data) return; emitMappingSymbol("$d"); LastEMS = EMS_Data; } void RISCVELFStreamer::emitInstructionsMappingSymbol() { if (LastEMS == EMS_Instructions) return; emitMappingSymbol("$x"); LastEMS = EMS_Instructions; } void RISCVELFStreamer::emitMappingSymbol(StringRef Name) { auto *Symbol = cast(getContext().createLocalSymbol(Name)); emitLabel(Symbol); Symbol->setType(ELF::STT_NOTYPE); Symbol->setBinding(ELF::STB_LOCAL); } void RISCVELFStreamer::changeSection(MCSection *Section, uint32_t Subsection) { // We have to keep track of the mapping symbol state of any sections we // use. Each one should start off as EMS_None, which is provided as the // default constructor by DenseMap::lookup. LastMappingSymbols[getPreviousSection().first] = LastEMS; LastEMS = LastMappingSymbols.lookup(Section); MCELFStreamer::changeSection(Section, Subsection); } void RISCVELFStreamer::emitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) { emitInstructionsMappingSymbol(); MCELFStreamer::emitInstruction(Inst, STI); } void RISCVELFStreamer::emitBytes(StringRef Data) { emitDataMappingSymbol(); MCELFStreamer::emitBytes(Data); } void RISCVELFStreamer::emitFill(const MCExpr &NumBytes, uint64_t FillValue, SMLoc Loc) { emitDataMappingSymbol(); MCELFStreamer::emitFill(NumBytes, FillValue, Loc); } void RISCVELFStreamer::emitValueImpl(const MCExpr *Value, unsigned Size, SMLoc Loc) { emitDataMappingSymbol(); MCELFStreamer::emitValueImpl(Value, Size, Loc); } namespace llvm { MCELFStreamer *createRISCVELFStreamer(MCContext &C, std::unique_ptr MAB, std::unique_ptr MOW, std::unique_ptr MCE) { RISCVELFStreamer *S = new RISCVELFStreamer(C, std::move(MAB), std::move(MOW), std::move(MCE)); return S; } } // namespace llvm