mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-04-02 13:12:09 +00:00

To be consistent with RISC-V branding guidelines https://riscv.org/about/risc-v-branding-guidelines/ Think we should be using RISC-V where possible. More patches will follow. Reviewed By: asb Differential Revision: https://reviews.llvm.org/D146449
215 lines
7.7 KiB
C++
215 lines
7.7 KiB
C++
//===-- 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"), STI(STI) {
|
|
MCAssembler &MCA = getStreamer().getAssembler();
|
|
const FeatureBitset &Features = STI.getFeatureBits();
|
|
auto &MAB = static_cast<RISCVAsmBackend &>(MCA.getBackend());
|
|
setTargetABI(RISCVABI::computeTargetABI(STI.getTargetTriple(), Features,
|
|
MAB.getTargetOptions().getABIName()));
|
|
}
|
|
|
|
RISCVELFStreamer &RISCVTargetELFStreamer::getStreamer() {
|
|
return static_cast<RISCVELFStreamer &>(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();
|
|
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;
|
|
if (Features[RISCV::FeatureStdExtZtso])
|
|
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");
|
|
}
|
|
|
|
MCA.setELFHeaderEFlags(EFlags);
|
|
}
|
|
|
|
void RISCVTargetELFStreamer::reset() {
|
|
AttributeSection = nullptr;
|
|
}
|
|
|
|
void RISCVTargetELFStreamer::emitDirectiveVariantCC(MCSymbol &Symbol) {
|
|
getStreamer().getAssembler().registerSymbol(Symbol);
|
|
cast<MCSymbolELF>(Symbol).setOther(ELF::STO_RISCV_VARIANT_CC);
|
|
}
|
|
|
|
bool RISCVELFStreamer::requiresFixups(MCContext &C, const MCExpr *Value,
|
|
const MCExpr *&LHS, const MCExpr *&RHS) {
|
|
const auto *MBE = dyn_cast<MCBinaryExpr>(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();
|
|
|
|
// Avoid ADD/SUB if Kind is not VK_None, e.g. A@plt - B + C.
|
|
if (E.getSymA()->getKind() != MCSymbolRefExpr::VK_None)
|
|
return false;
|
|
|
|
// If either symbol is in a text section, we need to delay the relocation
|
|
// evaluation as relaxation may alter the size of the symbol.
|
|
//
|
|
// Unfortunately, we cannot identify if the symbol was built with relaxation
|
|
// as we do not track the state per symbol or section. However, BFD will
|
|
// always emit the relocation and so we follow suit which avoids the need to
|
|
// track that information.
|
|
if (A.isInSection() && A.getSection().getKind().isText())
|
|
return true;
|
|
if (B.isInSection() && B.getSection().getKind().isText())
|
|
return true;
|
|
|
|
// If A is undefined and B is defined, we should emit ADD/SUB for A-B.
|
|
// Unfortunately, A may be defined later, but this requiresFixups call has to
|
|
// eagerly make a decision. For now, emit ADD/SUB unless A is .L*. This
|
|
// heuristic handles many temporary label differences for .debug_* and
|
|
// .apple_types sections.
|
|
//
|
|
// TODO Implement delayed relocation decision.
|
|
if (!A.isInSection() && !A.isTemporary() && B.isInSection())
|
|
return true;
|
|
|
|
// Support cross-section symbolic differences ...
|
|
return A.isInSection() && B.isInSection() &&
|
|
A.getSection().getName() != B.getSection().getName();
|
|
}
|
|
|
|
void RISCVELFStreamer::reset() {
|
|
static_cast<RISCVTargetStreamer *>(getTargetStreamer())->reset();
|
|
MCELFStreamer::reset();
|
|
}
|
|
|
|
void RISCVELFStreamer::emitValueImpl(const MCExpr *Value, unsigned Size,
|
|
SMLoc Loc) {
|
|
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());
|
|
|
|
MCFixupKind Add, Sub;
|
|
std::tie(Add, Sub) = RISCV::getRelocPairForSize(Size);
|
|
|
|
DF->getFixups().push_back(
|
|
MCFixup::create(DF->getContents().size(), A, Add, Loc));
|
|
DF->getFixups().push_back(
|
|
MCFixup::create(DF->getContents().size(), B, Sub, Loc));
|
|
|
|
DF->getContents().resize(DF->getContents().size() + Size, 0);
|
|
}
|
|
|
|
namespace llvm {
|
|
MCELFStreamer *createRISCVELFStreamer(MCContext &C,
|
|
std::unique_ptr<MCAsmBackend> MAB,
|
|
std::unique_ptr<MCObjectWriter> MOW,
|
|
std::unique_ptr<MCCodeEmitter> 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
|