//===-- RISCVELFStreamer.cpp - RISCV 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 RISCV 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"), STI(STI) { MCAssembler &MCA = getStreamer().getAssembler(); const FeatureBitset &Features = STI.getFeatureBits(); auto &MAB = static_cast(MCA.getBackend()); setTargetABI(RISCVABI::computeTargetABI(STI.getTargetTriple(), Features, MAB.getTargetOptions().getABIName())); } MCELFStreamer &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) { setAttributeItem(Attribute, Value, /*OverwriteExisting=*/true); } void RISCVTargetELFStreamer::emitTextAttribute(unsigned Attribute, StringRef String) { setAttributeItem(Attribute, String, /*OverwriteExisting=*/true); } void RISCVTargetELFStreamer::emitIntTextAttribute(unsigned Attribute, unsigned IntValue, StringRef StringValue) { setAttributeItems(Attribute, IntValue, StringValue, /*OverwriteExisting=*/true); } void RISCVTargetELFStreamer::finishAttributeSection() { if (Contents.empty()) return; if (AttributeSection) { Streamer.switchSection(AttributeSection); } else { MCAssembler &MCA = getStreamer().getAssembler(); AttributeSection = MCA.getContext().getELFSection( ".riscv.attributes", ELF::SHT_RISCV_ATTRIBUTES, 0); Streamer.switchSection(AttributeSection); Streamer.emitInt8(ELFAttrs::Format_Version); } // Vendor size + Vendor name + '\0' const size_t VendorHeaderSize = 4 + CurrentVendor.size() + 1; // Tag + Tag Size const size_t TagHeaderSize = 1 + 4; const size_t ContentsSize = calculateContentSize(); Streamer.emitInt32(VendorHeaderSize + TagHeaderSize + ContentsSize); Streamer.emitBytes(CurrentVendor); Streamer.emitInt8(0); // '\0' Streamer.emitInt8(ELFAttrs::File); Streamer.emitInt32(TagHeaderSize + ContentsSize); // Size should have been accounted for already, now // emit each field as its type (ULEB or String). for (AttributeItem item : Contents) { Streamer.emitULEB128IntValue(item.Tag); switch (item.Type) { default: llvm_unreachable("Invalid attribute type"); case AttributeType::Numeric: Streamer.emitULEB128IntValue(item.IntValue); break; case AttributeType::Text: Streamer.emitBytes(item.StringValue); Streamer.emitInt8(0); // '\0' break; case AttributeType::NumericAndText: Streamer.emitULEB128IntValue(item.IntValue); Streamer.emitBytes(item.StringValue); Streamer.emitInt8(0); // '\0' break; } } Contents.clear(); } size_t RISCVTargetELFStreamer::calculateContentSize() const { size_t Result = 0; for (AttributeItem item : Contents) { switch (item.Type) { case AttributeType::Hidden: break; case AttributeType::Numeric: Result += getULEB128Size(item.Tag); Result += getULEB128Size(item.IntValue); break; case AttributeType::Text: Result += getULEB128Size(item.Tag); Result += item.StringValue.size() + 1; // string + '\0' break; case AttributeType::NumericAndText: Result += getULEB128Size(item.Tag); Result += getULEB128Size(item.IntValue); Result += item.StringValue.size() + 1; // string + '\0'; break; } } return Result; } void RISCVTargetELFStreamer::finish() { RISCVTargetStreamer::finish(); MCAssembler &MCA = getStreamer().getAssembler(); const FeatureBitset &Features = STI.getFeatureBits(); RISCVABI::ABI ABI = getTargetABI(); unsigned EFlags = MCA.getELFHeaderEFlags(); if (Features[RISCV::FeatureStdExtC]) EFlags |= ELF::EF_RISCV_RVC; 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: EFlags |= ELF::EF_RISCV_RVE; break; case RISCVABI::ABI_Unknown: llvm_unreachable("Improperly initialised target ABI"); } MCA.setELFHeaderEFlags(EFlags); } void RISCVTargetELFStreamer::reset() { AttributeSection = nullptr; Contents.clear(); } namespace { class RISCVELFStreamer : public MCELFStreamer { static std::pair getRelocPairForSize(unsigned Size) { switch (Size) { default: llvm_unreachable("unsupported fixup size"); case 1: return std::make_pair(RISCV::fixup_riscv_add_8, RISCV::fixup_riscv_sub_8); case 2: return std::make_pair(RISCV::fixup_riscv_add_16, RISCV::fixup_riscv_sub_16); case 4: return std::make_pair(RISCV::fixup_riscv_add_32, RISCV::fixup_riscv_sub_32); case 8: return std::make_pair(RISCV::fixup_riscv_add_64, RISCV::fixup_riscv_sub_64); } } static bool requiresFixups(MCContext &C, const MCExpr *Value, const MCExpr *&LHS, const MCExpr *&RHS) { auto IsMetadataOrEHFrameSection = [](const MCSection &S) -> bool { // Additionally check .apple_names/.apple_types. They are fixed-size and // do not need fixups. llvm-dwarfdump --apple-names does not process // R_RISCV_{ADD,SUB}32 in them. return S.getKind().isMetadata() || S.getName() == ".eh_frame" || S.getName() == ".apple_names" || S.getName() == ".apple_types"; }; const auto *MBE = dyn_cast(Value); if (MBE == nullptr) return false; MCValue E; if (!Value->evaluateAsRelocatable(E, nullptr, nullptr)) return false; if (E.getSymA() == nullptr || E.getSymB() == nullptr) return false; const auto &A = E.getSymA()->getSymbol(); const auto &B = E.getSymB()->getSymbol(); LHS = MCBinaryExpr::create(MCBinaryExpr::Add, MCSymbolRefExpr::create(&A, C), MCConstantExpr::create(E.getConstant(), C), C); RHS = E.getSymB(); // TODO: when available, R_RISCV_n_PCREL should be preferred. // Avoid pairwise relocations for symbolic difference in debug and .eh_frame if (A.isInSection()) return !IsMetadataOrEHFrameSection(A.getSection()); if (B.isInSection()) return !IsMetadataOrEHFrameSection(B.getSection()); // as well as for absolute symbols. return !A.getName().empty() || !B.getName().empty(); } void reset() override { static_cast(getTargetStreamer())->reset(); MCELFStreamer::reset(); } public: RISCVELFStreamer(MCContext &C, std::unique_ptr MAB, std::unique_ptr MOW, std::unique_ptr MCE) : MCELFStreamer(C, std::move(MAB), std::move(MOW), std::move(MCE)) {} void emitValueImpl(const MCExpr *Value, unsigned Size, SMLoc Loc) override { const MCExpr *A, *B; if (!requiresFixups(getContext(), Value, A, B)) return MCELFStreamer::emitValueImpl(Value, Size, Loc); MCStreamer::emitValueImpl(Value, Size, Loc); MCDataFragment *DF = getOrCreateDataFragment(); flushPendingLabels(DF, DF->getContents().size()); MCDwarfLineEntry::make(this, getCurrentSectionOnly()); unsigned Add, Sub; std::tie(Add, Sub) = getRelocPairForSize(Size); DF->getFixups().push_back(MCFixup::create( DF->getContents().size(), A, static_cast(Add), Loc)); DF->getFixups().push_back(MCFixup::create( DF->getContents().size(), B, static_cast(Sub), Loc)); DF->getContents().resize(DF->getContents().size() + Size, 0); } }; } // namespace namespace llvm { MCELFStreamer *createRISCVELFStreamer(MCContext &C, std::unique_ptr MAB, std::unique_ptr MOW, std::unique_ptr MCE, bool RelaxAll) { RISCVELFStreamer *S = new RISCVELFStreamer(C, std::move(MAB), std::move(MOW), std::move(MCE)); S->getAssembler().setRelaxAll(RelaxAll); return S; } } // namespace llvm