Mapping symbols [1] are special ELF symbols that can be inserted to indicate regions of code or data. A sequence of data bytes is indicated by a `$d` (or `$d.<any>`) symbol pointing to its start while a sequence of instructions uses a `$x` (or `$x.<any>`) symbol. This can be used, for example, to assist disassembling a memory region containing both data and code. This patch implements mapping symbols for RISC-V, copying the implementation mostly from the AArch64 target. Note that the `$x<ISA>` mapping symbol, indicating an instruction sequence with a specific ISA extension, is not implemented by this patch. As far as I can tell, binutils doesn't implement this yet either. Note that this patch uses the same symbol naming convention as the AArch64 target: always use `$x.i` and `$d.i` (where `i` is a monotonically increasing counter). This differs from binutils where all symbols are named `$x` or `$d` (causing multiple symbol having the same name). I'm not not sure whether it makes more sense to avoid duplicate symbol names or be consistent with binutils. Note that the handling of nop-slides inserted for alignment differs from binutils: binutils always marks the nops as instructions (`$x`) while this patch doesn't insert a symbol for the nops (so the last inserted symbol is used). I believe binutil's behavior makes most sense but this seems difficult to implement in LLVM as the insertion of nops is handled by `RISCVAsmBackend`. At this point, inserting ELF symbols seems impossible. Any ideas for how to handle this would be appreciated. [1]: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc#mapping-symbol Depends on D156190 and D156236 Differential Revision: https://reviews.llvm.org/D153260
201 lines
6.8 KiB
C++
201 lines
6.8 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);
|
|
}
|
|
|
|
void RISCVELFStreamer::reset() {
|
|
static_cast<RISCVTargetStreamer *>(getTargetStreamer())->reset();
|
|
MCELFStreamer::reset();
|
|
MappingSymbolCounter = 0;
|
|
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<MCSymbolELF>(getContext().getOrCreateSymbol(
|
|
Name + "." + Twine(MappingSymbolCounter++)));
|
|
emitLabel(Symbol);
|
|
Symbol->setType(ELF::STT_NOTYPE);
|
|
Symbol->setBinding(ELF::STB_LOCAL);
|
|
}
|
|
|
|
void RISCVELFStreamer::changeSection(MCSection *Section,
|
|
const MCExpr *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<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
|