#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;
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()));
}
MCELFStreamer &RISCVTargetELFStreamer::getStreamer() {
return static_cast<MCELFStreamer &>(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, true);
}
void RISCVTargetELFStreamer::emitTextAttribute(unsigned Attribute,
StringRef String) {
setAttributeItem(Attribute, String, true);
}
void RISCVTargetELFStreamer::emitIntTextAttribute(unsigned Attribute,
unsigned IntValue,
StringRef StringValue) {
setAttributeItems(Attribute, IntValue, StringValue,
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);
}
const size_t VendorHeaderSize = 4 + CurrentVendor.size() + 1;
const size_t TagHeaderSize = 1 + 4;
const size_t ContentsSize = calculateContentSize();
Streamer.emitInt32(VendorHeaderSize + TagHeaderSize + ContentsSize);
Streamer.emitBytes(CurrentVendor);
Streamer.emitInt8(0);
Streamer.emitInt8(ELFAttrs::File);
Streamer.emitInt32(TagHeaderSize + ContentsSize);
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); break;
case AttributeType::NumericAndText:
Streamer.emitULEB128IntValue(item.IntValue);
Streamer.emitBytes(item.StringValue);
Streamer.emitInt8(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; break;
case AttributeType::NumericAndText:
Result += getULEB128Size(item.Tag);
Result += getULEB128Size(item.IntValue);
Result += item.StringValue.size() + 1; 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<unsigned, unsigned> 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 {
return S.getKind().isMetadata() || S.getName() == ".eh_frame" ||
S.getName() == ".apple_names" || S.getName() == ".apple_types";
};
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();
if (A.isInSection())
return !IsMetadataOrEHFrameSection(A.getSection());
if (B.isInSection())
return !IsMetadataOrEHFrameSection(B.getSection());
return !A.getName().empty() || !B.getName().empty();
}
void reset() override {
static_cast<RISCVTargetStreamer *>(getTargetStreamer())->reset();
MCELFStreamer::reset();
}
public:
RISCVELFStreamer(MCContext &C, std::unique_ptr<MCAsmBackend> MAB,
std::unique_ptr<MCObjectWriter> MOW,
std::unique_ptr<MCCodeEmitter> 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<MCFixupKind>(Add), Loc));
DF->getFixups().push_back(MCFixup::create(
DF->getContents().size(), B, static_cast<MCFixupKind>(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;
}
}