mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 02:33:06 +01:00
RISCV: adjust handling of relocation emission for RISCV
This re-architects the RISCV relocation handling to bring the implementation closer in line with the implementation in binutils. We would previously aggressively resolve the relocation. With this restructuring, we always will emit a paired relocation for any symbolic difference of the type of S±T[±C] where S and T are labels and C is a constant. GAS has a special target hook controlled by `RELOC_EXPANSION_POSSIBLE` which indicates that a fixup may be expanded into multiple relocations. This is used by the RISCV backend to always emit a paired relocation - either ADD[WIDTH] + SUB[WIDTH] for text relocations or SET[WIDTH] + SUB[WIDTH] for a debug info relocation. Irrespective of whether linker relaxation support is enabled, symbolic difference is always emitted as a paired relocation. This change also sinks the target specific behaviour down into the target specific area rather than exposing it to the shared relocation handling. In the process, we also sink the "special" handling for debug information down into the RISCV target. Although this improves the path for the other targets, this is not necessarily entirely ideal either. The changes in the debug info emission could be done through another type of hook as this functionality would be required by any other target which wishes to do linker relaxation. However, as there are no other targets in LLVM which currently do this, this is a reasonable thing to do until such time as the code needs to be shared. Improve the handling of the relocation (and add a reduced test case from the Linux kernel) to ensure that we handle complex expressions for symbolic difference. This ensures that we correct relocate symbols with the adddends normalized and associated with the addition portion of the paired relocation. This change also addresses some review comments from Alex Bradbury about the relocations meant for use in the DWARF CFA being named incorrectly (using ADD6 instead of SET6) in the original change which introduced the relocation type. This resolves the issues with the symbolic difference emission sufficiently to enable building the Linux kernel with clang+IAS+lld (without linker relaxation). Resolves PR50153, PR50156! Fixes: ClangBuiltLinux/linux#1023, ClangBuiltLinux/linux#1143 Reviewed By: nickdesaulniers, maskray Differential Revision: https://reviews.llvm.org/D103539
This commit is contained in:
parent
84970078e4
commit
f56e4f6d3d
@ -129,10 +129,6 @@ public:
|
||||
uint64_t Value, bool IsResolved,
|
||||
const MCSubtargetInfo *STI) const = 0;
|
||||
|
||||
/// Check whether the given target requires emitting differences of two
|
||||
/// symbols as a set of relocations.
|
||||
virtual bool requiresDiffExpressionRelocations() const { return false; }
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Target Relaxation Interfaces
|
||||
@ -169,6 +165,16 @@ public:
|
||||
virtual void relaxInstruction(MCInst &Inst,
|
||||
const MCSubtargetInfo &STI) const {};
|
||||
|
||||
virtual bool relaxDwarfLineAddr(MCDwarfLineAddrFragment &DF,
|
||||
MCAsmLayout &Layout, bool &WasRelaxed) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool relaxDwarfCFA(MCDwarfCallFrameFragment &DF, MCAsmLayout &Layout,
|
||||
bool &WasRelaxed) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
/// Returns the minimum size of a nop in bytes on this target. The assembler
|
||||
|
@ -387,13 +387,6 @@ public:
|
||||
static void Encode(MCContext &Context, MCDwarfLineTableParams Params,
|
||||
int64_t LineDelta, uint64_t AddrDelta, raw_ostream &OS);
|
||||
|
||||
/// Utility function to encode a Dwarf pair of LineDelta and AddrDeltas using
|
||||
/// fixed length operands. Returns (Offset, Size, SetDelta).
|
||||
static std::tuple<uint32_t, uint32_t, bool> fixedEncode(MCContext &Context,
|
||||
int64_t LineDelta,
|
||||
uint64_t AddrDelta,
|
||||
raw_ostream &OS);
|
||||
|
||||
/// Utility function to emit the encoding to a streamer.
|
||||
static void Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params,
|
||||
int64_t LineDelta, uint64_t AddrDelta);
|
||||
@ -667,8 +660,7 @@ public:
|
||||
static void Emit(MCObjectStreamer &streamer, MCAsmBackend *MAB, bool isEH);
|
||||
static void EmitAdvanceLoc(MCObjectStreamer &Streamer, uint64_t AddrDelta);
|
||||
static void EncodeAdvanceLoc(MCContext &Context, uint64_t AddrDelta,
|
||||
raw_ostream &OS, uint32_t *Offset = nullptr,
|
||||
uint32_t *Size = nullptr);
|
||||
raw_ostream &OS);
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
@ -41,16 +41,6 @@ enum MCFixupKind {
|
||||
FK_SecRel_2, ///< A two-byte section relative fixup.
|
||||
FK_SecRel_4, ///< A four-byte section relative fixup.
|
||||
FK_SecRel_8, ///< A eight-byte section relative fixup.
|
||||
FK_Data_Add_1, ///< A one-byte add fixup.
|
||||
FK_Data_Add_2, ///< A two-byte add fixup.
|
||||
FK_Data_Add_4, ///< A four-byte add fixup.
|
||||
FK_Data_Add_8, ///< A eight-byte add fixup.
|
||||
FK_Data_Add_6b, ///< A six-bits add fixup.
|
||||
FK_Data_Sub_1, ///< A one-byte sub fixup.
|
||||
FK_Data_Sub_2, ///< A two-byte sub fixup.
|
||||
FK_Data_Sub_4, ///< A four-byte sub fixup.
|
||||
FK_Data_Sub_8, ///< A eight-byte sub fixup.
|
||||
FK_Data_Sub_6b, ///< A six-bits sub fixup.
|
||||
|
||||
FirstTargetFixupKind = 128,
|
||||
|
||||
@ -105,28 +95,6 @@ public:
|
||||
return FI;
|
||||
}
|
||||
|
||||
/// Return a fixup corresponding to the add half of a add/sub fixup pair for
|
||||
/// the given Fixup.
|
||||
static MCFixup createAddFor(const MCFixup &Fixup) {
|
||||
MCFixup FI;
|
||||
FI.Value = Fixup.getValue();
|
||||
FI.Offset = Fixup.getOffset();
|
||||
FI.Kind = getAddKindForKind(Fixup.getKind());
|
||||
FI.Loc = Fixup.getLoc();
|
||||
return FI;
|
||||
}
|
||||
|
||||
/// Return a fixup corresponding to the sub half of a add/sub fixup pair for
|
||||
/// the given Fixup.
|
||||
static MCFixup createSubFor(const MCFixup &Fixup) {
|
||||
MCFixup FI;
|
||||
FI.Value = Fixup.getValue();
|
||||
FI.Offset = Fixup.getOffset();
|
||||
FI.Kind = getSubKindForKind(Fixup.getKind());
|
||||
FI.Loc = Fixup.getLoc();
|
||||
return FI;
|
||||
}
|
||||
|
||||
MCFixupKind getKind() const { return Kind; }
|
||||
|
||||
unsigned getTargetKind() const { return Kind; }
|
||||
@ -172,32 +140,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the generic fixup kind for an addition with a given size. It
|
||||
/// is an error to pass an unsupported size.
|
||||
static MCFixupKind getAddKindForKind(MCFixupKind Kind) {
|
||||
switch (Kind) {
|
||||
default: llvm_unreachable("Unknown type to convert!");
|
||||
case FK_Data_1: return FK_Data_Add_1;
|
||||
case FK_Data_2: return FK_Data_Add_2;
|
||||
case FK_Data_4: return FK_Data_Add_4;
|
||||
case FK_Data_8: return FK_Data_Add_8;
|
||||
case FK_Data_6b: return FK_Data_Add_6b;
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the generic fixup kind for an subtraction with a given size. It
|
||||
/// is an error to pass an unsupported size.
|
||||
static MCFixupKind getSubKindForKind(MCFixupKind Kind) {
|
||||
switch (Kind) {
|
||||
default: llvm_unreachable("Unknown type to convert!");
|
||||
case FK_Data_1: return FK_Data_Sub_1;
|
||||
case FK_Data_2: return FK_Data_Sub_2;
|
||||
case FK_Data_4: return FK_Data_Sub_4;
|
||||
case FK_Data_8: return FK_Data_Sub_8;
|
||||
case FK_Data_6b: return FK_Data_Sub_6b;
|
||||
}
|
||||
}
|
||||
|
||||
SMLoc getLoc() const { return Loc; }
|
||||
};
|
||||
|
||||
|
@ -95,16 +95,7 @@ const MCFixupKindInfo &MCAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
|
||||
{"FK_SecRel_2", 0, 16, 0},
|
||||
{"FK_SecRel_4", 0, 32, 0},
|
||||
{"FK_SecRel_8", 0, 64, 0},
|
||||
{"FK_Data_Add_1", 0, 8, 0},
|
||||
{"FK_Data_Add_2", 0, 16, 0},
|
||||
{"FK_Data_Add_4", 0, 32, 0},
|
||||
{"FK_Data_Add_8", 0, 64, 0},
|
||||
{"FK_Data_Add_6b", 0, 6, 0},
|
||||
{"FK_Data_Sub_1", 0, 8, 0},
|
||||
{"FK_Data_Sub_2", 0, 16, 0},
|
||||
{"FK_Data_Sub_4", 0, 32, 0},
|
||||
{"FK_Data_Sub_8", 0, 64, 0},
|
||||
{"FK_Data_Sub_6b", 0, 6, 0}};
|
||||
};
|
||||
|
||||
assert((size_t)Kind <= array_lengthof(Builtins) && "Unknown fixup kind");
|
||||
return Builtins[Kind];
|
||||
|
@ -792,26 +792,7 @@ MCAssembler::handleFixup(const MCAsmLayout &Layout, MCFragment &F,
|
||||
// The fixup was unresolved, we need a relocation. Inform the object
|
||||
// writer of the relocation, and give it an opportunity to adjust the
|
||||
// fixup value if need be.
|
||||
if (Target.getSymA() && Target.getSymB() &&
|
||||
getBackend().requiresDiffExpressionRelocations()) {
|
||||
// The fixup represents the difference between two symbols, which the
|
||||
// backend has indicated must be resolved at link time. Split up the fixup
|
||||
// into two relocations, one for the add, and one for the sub, and emit
|
||||
// both of these. The constant will be associated with the add half of the
|
||||
// expression.
|
||||
MCFixup FixupAdd = MCFixup::createAddFor(Fixup);
|
||||
MCValue TargetAdd =
|
||||
MCValue::get(Target.getSymA(), nullptr, Target.getConstant());
|
||||
getWriter().recordRelocation(*this, Layout, &F, FixupAdd, TargetAdd,
|
||||
FixedValue);
|
||||
MCFixup FixupSub = MCFixup::createSubFor(Fixup);
|
||||
MCValue TargetSub = MCValue::get(Target.getSymB());
|
||||
getWriter().recordRelocation(*this, Layout, &F, FixupSub, TargetSub,
|
||||
FixedValue);
|
||||
} else {
|
||||
getWriter().recordRelocation(*this, Layout, &F, Fixup, Target,
|
||||
FixedValue);
|
||||
}
|
||||
getWriter().recordRelocation(*this, Layout, &F, Fixup, Target, FixedValue);
|
||||
}
|
||||
return std::make_tuple(Target, FixedValue, IsResolved);
|
||||
}
|
||||
@ -1100,6 +1081,11 @@ bool MCAssembler::relaxBoundaryAlign(MCAsmLayout &Layout,
|
||||
|
||||
bool MCAssembler::relaxDwarfLineAddr(MCAsmLayout &Layout,
|
||||
MCDwarfLineAddrFragment &DF) {
|
||||
|
||||
bool WasRelaxed;
|
||||
if (getBackend().relaxDwarfLineAddr(DF, Layout, WasRelaxed))
|
||||
return WasRelaxed;
|
||||
|
||||
MCContext &Context = Layout.getAssembler().getContext();
|
||||
uint64_t OldSize = DF.getContents().size();
|
||||
int64_t AddrDelta;
|
||||
@ -1113,33 +1099,17 @@ bool MCAssembler::relaxDwarfLineAddr(MCAsmLayout &Layout,
|
||||
raw_svector_ostream OSE(Data);
|
||||
DF.getFixups().clear();
|
||||
|
||||
if (!getBackend().requiresDiffExpressionRelocations()) {
|
||||
MCDwarfLineAddr::Encode(Context, getDWARFLinetableParams(), LineDelta,
|
||||
AddrDelta, OSE);
|
||||
} else {
|
||||
uint32_t Offset;
|
||||
uint32_t Size;
|
||||
bool SetDelta;
|
||||
std::tie(Offset, Size, SetDelta) =
|
||||
MCDwarfLineAddr::fixedEncode(Context, LineDelta, AddrDelta, OSE);
|
||||
// Add Fixups for address delta or new address.
|
||||
const MCExpr *FixupExpr;
|
||||
if (SetDelta) {
|
||||
FixupExpr = &DF.getAddrDelta();
|
||||
} else {
|
||||
const MCBinaryExpr *ABE = cast<MCBinaryExpr>(&DF.getAddrDelta());
|
||||
FixupExpr = ABE->getLHS();
|
||||
}
|
||||
DF.getFixups().push_back(
|
||||
MCFixup::create(Offset, FixupExpr,
|
||||
MCFixup::getKindForSize(Size, false /*isPCRel*/)));
|
||||
}
|
||||
|
||||
return OldSize != Data.size();
|
||||
}
|
||||
|
||||
bool MCAssembler::relaxDwarfCallFrameFragment(MCAsmLayout &Layout,
|
||||
MCDwarfCallFrameFragment &DF) {
|
||||
bool WasRelaxed;
|
||||
if (getBackend().relaxDwarfCFA(DF, Layout, WasRelaxed))
|
||||
return WasRelaxed;
|
||||
|
||||
MCContext &Context = Layout.getAssembler().getContext();
|
||||
uint64_t OldSize = DF.getContents().size();
|
||||
int64_t AddrDelta;
|
||||
@ -1151,20 +1121,7 @@ bool MCAssembler::relaxDwarfCallFrameFragment(MCAsmLayout &Layout,
|
||||
raw_svector_ostream OSE(Data);
|
||||
DF.getFixups().clear();
|
||||
|
||||
if (getBackend().requiresDiffExpressionRelocations()) {
|
||||
uint32_t Offset;
|
||||
uint32_t Size;
|
||||
MCDwarfFrameEmitter::EncodeAdvanceLoc(Context, AddrDelta, OSE, &Offset,
|
||||
&Size);
|
||||
if (Size) {
|
||||
DF.getFixups().push_back(MCFixup::create(
|
||||
Offset, &DF.getAddrDelta(),
|
||||
MCFixup::getKindForSizeInBits(Size /*In bits.*/, false /*isPCRel*/)));
|
||||
}
|
||||
} else {
|
||||
MCDwarfFrameEmitter::EncodeAdvanceLoc(Context, AddrDelta, OSE);
|
||||
}
|
||||
|
||||
return OldSize != Data.size();
|
||||
}
|
||||
|
||||
@ -1194,10 +1151,6 @@ bool MCAssembler::relaxPseudoProbeAddr(MCAsmLayout &Layout,
|
||||
raw_svector_ostream OSE(Data);
|
||||
PF.getFixups().clear();
|
||||
|
||||
// Relocations should not be needed in general except on RISC-V which we are
|
||||
// not targeted for now.
|
||||
assert(!getBackend().requiresDiffExpressionRelocations() &&
|
||||
"cannot relax relocations");
|
||||
// AddrDelta is a signed integer
|
||||
encodeSLEB128(AddrDelta, OSE, OldSize);
|
||||
return OldSize != Data.size();
|
||||
|
@ -734,54 +734,6 @@ void MCDwarfLineAddr::Encode(MCContext &Context, MCDwarfLineTableParams Params,
|
||||
}
|
||||
}
|
||||
|
||||
std::tuple<uint32_t, uint32_t, bool>
|
||||
MCDwarfLineAddr::fixedEncode(MCContext &Context, int64_t LineDelta,
|
||||
uint64_t AddrDelta, raw_ostream &OS) {
|
||||
uint32_t Offset, Size;
|
||||
if (LineDelta != INT64_MAX) {
|
||||
OS << char(dwarf::DW_LNS_advance_line);
|
||||
encodeSLEB128(LineDelta, OS);
|
||||
}
|
||||
|
||||
// Use address delta to adjust address or use absolute address to adjust
|
||||
// address.
|
||||
bool SetDelta;
|
||||
// According to DWARF spec., the DW_LNS_fixed_advance_pc opcode takes a
|
||||
// single uhalf (unencoded) operand. So, the maximum value of AddrDelta
|
||||
// is 65535. We set a conservative upper bound for it for relaxation.
|
||||
if (AddrDelta > 60000) {
|
||||
const MCAsmInfo *asmInfo = Context.getAsmInfo();
|
||||
unsigned AddrSize = asmInfo->getCodePointerSize();
|
||||
|
||||
OS << char(dwarf::DW_LNS_extended_op);
|
||||
encodeULEB128(1 + AddrSize, OS);
|
||||
OS << char(dwarf::DW_LNE_set_address);
|
||||
// Generate fixup for the address.
|
||||
Offset = OS.tell();
|
||||
Size = AddrSize;
|
||||
SetDelta = false;
|
||||
OS.write_zeros(AddrSize);
|
||||
} else {
|
||||
OS << char(dwarf::DW_LNS_fixed_advance_pc);
|
||||
// Generate fixup for 2-bytes address delta.
|
||||
Offset = OS.tell();
|
||||
Size = 2;
|
||||
SetDelta = true;
|
||||
OS << char(0);
|
||||
OS << char(0);
|
||||
}
|
||||
|
||||
if (LineDelta == INT64_MAX) {
|
||||
OS << char(dwarf::DW_LNS_extended_op);
|
||||
OS << char(1);
|
||||
OS << char(dwarf::DW_LNE_end_sequence);
|
||||
} else {
|
||||
OS << char(dwarf::DW_LNS_copy);
|
||||
}
|
||||
|
||||
return std::make_tuple(Offset, Size, SetDelta);
|
||||
}
|
||||
|
||||
// Utility function to write a tuple for .debug_abbrev.
|
||||
static void EmitAbbrev(MCStreamer *MCOS, uint64_t Name, uint64_t Form) {
|
||||
MCOS->emitULEB128IntValue(Name);
|
||||
@ -1940,54 +1892,28 @@ void MCDwarfFrameEmitter::EmitAdvanceLoc(MCObjectStreamer &Streamer,
|
||||
}
|
||||
|
||||
void MCDwarfFrameEmitter::EncodeAdvanceLoc(MCContext &Context,
|
||||
uint64_t AddrDelta, raw_ostream &OS,
|
||||
uint32_t *Offset, uint32_t *Size) {
|
||||
uint64_t AddrDelta,
|
||||
raw_ostream &OS) {
|
||||
// Scale the address delta by the minimum instruction length.
|
||||
AddrDelta = ScaleAddrDelta(Context, AddrDelta);
|
||||
|
||||
bool WithFixups = false;
|
||||
if (Offset && Size)
|
||||
WithFixups = true;
|
||||
if (AddrDelta == 0)
|
||||
return;
|
||||
|
||||
support::endianness E =
|
||||
Context.getAsmInfo()->isLittleEndian() ? support::little : support::big;
|
||||
if (AddrDelta == 0) {
|
||||
if (WithFixups) {
|
||||
*Offset = 0;
|
||||
*Size = 0;
|
||||
}
|
||||
} else if (isUIntN(6, AddrDelta)) {
|
||||
|
||||
if (isUIntN(6, AddrDelta)) {
|
||||
uint8_t Opcode = dwarf::DW_CFA_advance_loc | AddrDelta;
|
||||
if (WithFixups) {
|
||||
*Offset = OS.tell();
|
||||
*Size = 6;
|
||||
OS << uint8_t(dwarf::DW_CFA_advance_loc);
|
||||
} else
|
||||
OS << Opcode;
|
||||
} else if (isUInt<8>(AddrDelta)) {
|
||||
OS << uint8_t(dwarf::DW_CFA_advance_loc1);
|
||||
if (WithFixups) {
|
||||
*Offset = OS.tell();
|
||||
*Size = 8;
|
||||
OS.write_zeros(1);
|
||||
} else
|
||||
OS << uint8_t(AddrDelta);
|
||||
} else if (isUInt<16>(AddrDelta)) {
|
||||
OS << uint8_t(dwarf::DW_CFA_advance_loc2);
|
||||
if (WithFixups) {
|
||||
*Offset = OS.tell();
|
||||
*Size = 16;
|
||||
OS.write_zeros(2);
|
||||
} else
|
||||
support::endian::write<uint16_t>(OS, AddrDelta, E);
|
||||
} else {
|
||||
assert(isUInt<32>(AddrDelta));
|
||||
OS << uint8_t(dwarf::DW_CFA_advance_loc4);
|
||||
if (WithFixups) {
|
||||
*Offset = OS.tell();
|
||||
*Size = 32;
|
||||
OS.write_zeros(4);
|
||||
} else
|
||||
support::endian::write<uint32_t>(OS, AddrDelta, E);
|
||||
}
|
||||
}
|
||||
|
@ -671,24 +671,6 @@ static void AttemptToFoldSymbolOffsetDifference(
|
||||
}
|
||||
}
|
||||
|
||||
static bool canFold(const MCAssembler *Asm, const MCSymbolRefExpr *A,
|
||||
const MCSymbolRefExpr *B, bool InSet) {
|
||||
if (InSet)
|
||||
return true;
|
||||
|
||||
if (!Asm->getBackend().requiresDiffExpressionRelocations())
|
||||
return true;
|
||||
|
||||
const MCSymbol &CheckSym = A ? A->getSymbol() : B->getSymbol();
|
||||
if (!CheckSym.isInSection())
|
||||
return true;
|
||||
|
||||
if (!CheckSym.getSection().hasInstructions())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Evaluate the result of an add between (conceptually) two MCValues.
|
||||
///
|
||||
/// This routine conceptually attempts to construct an MCValue:
|
||||
@ -725,11 +707,8 @@ EvaluateSymbolicAdd(const MCAssembler *Asm, const MCAsmLayout *Layout,
|
||||
assert((!Layout || Asm) &&
|
||||
"Must have an assembler object if layout is given!");
|
||||
|
||||
// If we have a layout, we can fold resolved differences. Do not do this if
|
||||
// the backend requires this to be emitted as individual relocations, unless
|
||||
// the InSet flag is set to get the current difference anyway (used for
|
||||
// example to calculate symbol sizes).
|
||||
if (Asm && canFold(Asm, LHS_A, LHS_B, InSet)) {
|
||||
// If we have a layout, we can fold resolved differences.
|
||||
if (Asm) {
|
||||
// First, fold out any differences which are fully resolved. By
|
||||
// reassociating terms in
|
||||
// Result = (LHS_A - LHS_B + LHS_Cst) + (RHS_A - RHS_B + RHS_Cst).
|
||||
|
@ -127,12 +127,9 @@ void MCObjectStreamer::resolvePendingFixups() {
|
||||
|
||||
// As a compile-time optimization, avoid allocating and evaluating an MCExpr
|
||||
// tree for (Hi - Lo) when Hi and Lo are offsets into the same fragment.
|
||||
static Optional<uint64_t>
|
||||
absoluteSymbolDiff(MCAssembler &Asm, const MCSymbol *Hi, const MCSymbol *Lo) {
|
||||
static Optional<uint64_t> absoluteSymbolDiff(const MCSymbol *Hi,
|
||||
const MCSymbol *Lo) {
|
||||
assert(Hi && Lo);
|
||||
if (Asm.getBackendPtr()->requiresDiffExpressionRelocations())
|
||||
return None;
|
||||
|
||||
if (!Hi->getFragment() || Hi->getFragment() != Lo->getFragment() ||
|
||||
Hi->isVariable() || Lo->isVariable())
|
||||
return None;
|
||||
@ -143,19 +140,17 @@ absoluteSymbolDiff(MCAssembler &Asm, const MCSymbol *Hi, const MCSymbol *Lo) {
|
||||
void MCObjectStreamer::emitAbsoluteSymbolDiff(const MCSymbol *Hi,
|
||||
const MCSymbol *Lo,
|
||||
unsigned Size) {
|
||||
if (Optional<uint64_t> Diff = absoluteSymbolDiff(getAssembler(), Hi, Lo)) {
|
||||
emitIntValue(*Diff, Size);
|
||||
return;
|
||||
}
|
||||
if (!getAssembler().getContext().getTargetTriple().isRISCV())
|
||||
if (Optional<uint64_t> Diff = absoluteSymbolDiff(Hi, Lo))
|
||||
return emitIntValue(*Diff, Size);
|
||||
MCStreamer::emitAbsoluteSymbolDiff(Hi, Lo, Size);
|
||||
}
|
||||
|
||||
void MCObjectStreamer::emitAbsoluteSymbolDiffAsULEB128(const MCSymbol *Hi,
|
||||
const MCSymbol *Lo) {
|
||||
if (Optional<uint64_t> Diff = absoluteSymbolDiff(getAssembler(), Hi, Lo)) {
|
||||
emitULEB128IntValue(*Diff);
|
||||
return;
|
||||
}
|
||||
if (!getAssembler().getContext().getTargetTriple().isRISCV())
|
||||
if (Optional<uint64_t> Diff = absoluteSymbolDiff(Hi, Lo))
|
||||
return emitULEB128IntValue(*Diff);
|
||||
MCStreamer::emitAbsoluteSymbolDiffAsULEB128(Hi, Lo);
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "RISCVAsmBackend.h"
|
||||
#include "RISCVMCExpr.h"
|
||||
#include "llvm/ADT/APInt.h"
|
||||
#include "llvm/MC/MCAsmInfo.h"
|
||||
#include "llvm/MC/MCAsmLayout.h"
|
||||
#include "llvm/MC/MCAssembler.h"
|
||||
#include "llvm/MC/MCContext.h"
|
||||
@ -18,7 +19,10 @@
|
||||
#include "llvm/MC/MCObjectWriter.h"
|
||||
#include "llvm/MC/MCSymbol.h"
|
||||
#include "llvm/MC/MCValue.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/EndianStream.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/LEB128.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
using namespace llvm;
|
||||
@ -70,7 +74,26 @@ RISCVAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
|
||||
{"fixup_riscv_call", 0, 64, MCFixupKindInfo::FKF_IsPCRel},
|
||||
{"fixup_riscv_call_plt", 0, 64, MCFixupKindInfo::FKF_IsPCRel},
|
||||
{"fixup_riscv_relax", 0, 0, 0},
|
||||
{"fixup_riscv_align", 0, 0, 0}};
|
||||
{"fixup_riscv_align", 0, 0, 0},
|
||||
|
||||
{"fixup_riscv_set_8", 0, 8, 0},
|
||||
{"fixup_riscv_add_8", 0, 8, 0},
|
||||
{"fixup_riscv_sub_8", 0, 8, 0},
|
||||
|
||||
{"fixup_riscv_set_16", 0, 16, 0},
|
||||
{"fixup_riscv_add_16", 0, 16, 0},
|
||||
{"fixup_riscv_sub_16", 0, 16, 0},
|
||||
|
||||
{"fixup_riscv_set_32", 0, 32, 0},
|
||||
{"fixup_riscv_add_32", 0, 32, 0},
|
||||
{"fixup_riscv_sub_32", 0, 32, 0},
|
||||
|
||||
{"fixup_riscv_add_64", 0, 64, 0},
|
||||
{"fixup_riscv_sub_64", 0, 64, 0},
|
||||
|
||||
{"fixup_riscv_set_6b", 2, 6, 0},
|
||||
{"fixup_riscv_sub_6b", 2, 6, 0},
|
||||
};
|
||||
static_assert((array_lengthof(Infos)) == RISCV::NumTargetFixupKinds,
|
||||
"Not all fixup kinds added to Infos array");
|
||||
|
||||
@ -179,6 +202,134 @@ void RISCVAsmBackend::relaxInstruction(MCInst &Inst,
|
||||
Inst = std::move(Res);
|
||||
}
|
||||
|
||||
bool RISCVAsmBackend::relaxDwarfLineAddr(MCDwarfLineAddrFragment &DF,
|
||||
MCAsmLayout &Layout,
|
||||
bool &WasRelaxed) const {
|
||||
MCContext &C = Layout.getAssembler().getContext();
|
||||
|
||||
int64_t LineDelta = DF.getLineDelta();
|
||||
const MCExpr &AddrDelta = DF.getAddrDelta();
|
||||
SmallVectorImpl<char> &Data = DF.getContents();
|
||||
SmallVectorImpl<MCFixup> &Fixups = DF.getFixups();
|
||||
size_t OldSize = Data.size();
|
||||
|
||||
int64_t Value;
|
||||
bool IsAbsolute = AddrDelta.evaluateKnownAbsolute(Value, Layout);
|
||||
assert(IsAbsolute && "CFA with invalid expression");
|
||||
(void)IsAbsolute;
|
||||
|
||||
Data.clear();
|
||||
Fixups.clear();
|
||||
raw_svector_ostream OS(Data);
|
||||
|
||||
// INT64_MAX is a signal that this is actually a DW_LNE_end_sequence.
|
||||
if (LineDelta != INT64_MAX) {
|
||||
OS << uint8_t(dwarf::DW_LNS_advance_line);
|
||||
encodeSLEB128(LineDelta, OS);
|
||||
}
|
||||
|
||||
unsigned Offset;
|
||||
std::pair<unsigned, unsigned> Fixup;
|
||||
|
||||
// According to the DWARF specification, the `DW_LNS_fixed_advance_pc` opcode
|
||||
// takes a single unsigned half (unencoded) operand. The maximum encodable
|
||||
// value is therefore 65535. Set a conservative upper bound for relaxation.
|
||||
if (Value > 60000) {
|
||||
unsigned PtrSize = C.getAsmInfo()->getCodePointerSize();
|
||||
|
||||
OS << uint8_t(dwarf::DW_LNS_extended_op);
|
||||
encodeULEB128(PtrSize + 1, OS);
|
||||
|
||||
OS << uint8_t(dwarf::DW_LNE_set_address);
|
||||
Offset = OS.tell();
|
||||
Fixup = PtrSize == 4 ? std::make_pair(RISCV::fixup_riscv_add_32,
|
||||
RISCV::fixup_riscv_sub_32)
|
||||
: std::make_pair(RISCV::fixup_riscv_add_64,
|
||||
RISCV::fixup_riscv_sub_64);
|
||||
OS.write_zeros(PtrSize);
|
||||
} else {
|
||||
OS << uint8_t(dwarf::DW_LNS_fixed_advance_pc);
|
||||
Offset = OS.tell();
|
||||
Fixup = {RISCV::fixup_riscv_add_16, RISCV::fixup_riscv_sub_16};
|
||||
support::endian::write<uint16_t>(OS, 0, support::little);
|
||||
}
|
||||
|
||||
const MCBinaryExpr &MBE = cast<MCBinaryExpr>(AddrDelta);
|
||||
Fixups.push_back(MCFixup::create(
|
||||
Offset, MBE.getLHS(), static_cast<MCFixupKind>(std::get<0>(Fixup))));
|
||||
Fixups.push_back(MCFixup::create(
|
||||
Offset, MBE.getRHS(), static_cast<MCFixupKind>(std::get<1>(Fixup))));
|
||||
|
||||
if (LineDelta == INT64_MAX) {
|
||||
OS << uint8_t(dwarf::DW_LNS_extended_op);
|
||||
OS << uint8_t(1);
|
||||
OS << uint8_t(dwarf::DW_LNE_end_sequence);
|
||||
} else {
|
||||
OS << uint8_t(dwarf::DW_LNS_copy);
|
||||
}
|
||||
|
||||
WasRelaxed = OldSize != Data.size();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RISCVAsmBackend::relaxDwarfCFA(MCDwarfCallFrameFragment &DF,
|
||||
MCAsmLayout &Layout,
|
||||
bool &WasRelaxed) const {
|
||||
MCContext &C = Layout.getAssembler().getContext();
|
||||
|
||||
const MCExpr &AddrDelta = DF.getAddrDelta();
|
||||
SmallVectorImpl<char> &Data = DF.getContents();
|
||||
SmallVectorImpl<MCFixup> &Fixups = DF.getFixups();
|
||||
size_t OldSize = Data.size();
|
||||
|
||||
int64_t Value;
|
||||
bool IsAbsolute = AddrDelta.evaluateKnownAbsolute(Value, Layout);
|
||||
assert(IsAbsolute && "CFA with invalid expression");
|
||||
(void)IsAbsolute;
|
||||
|
||||
Data.clear();
|
||||
Fixups.clear();
|
||||
raw_svector_ostream OS(Data);
|
||||
|
||||
assert(C.getAsmInfo()->getMinInstAlignment() == 1 &&
|
||||
"expected 1-byte alignment");
|
||||
if (Value == 0) {
|
||||
WasRelaxed = OldSize != Data.size();
|
||||
return true;
|
||||
}
|
||||
|
||||
auto AddFixups = [&Fixups, &AddrDelta](unsigned Offset,
|
||||
std::pair<unsigned, unsigned> Fixup) {
|
||||
const MCBinaryExpr &MBE = cast<MCBinaryExpr>(AddrDelta);
|
||||
Fixups.push_back(MCFixup::create(
|
||||
Offset, MBE.getLHS(), static_cast<MCFixupKind>(std::get<0>(Fixup))));
|
||||
Fixups.push_back(MCFixup::create(
|
||||
Offset, MBE.getRHS(), static_cast<MCFixupKind>(std::get<1>(Fixup))));
|
||||
};
|
||||
|
||||
if (isUIntN(6, Value)) {
|
||||
OS << uint8_t(dwarf::DW_CFA_advance_loc);
|
||||
AddFixups(0, {RISCV::fixup_riscv_set_6b, RISCV::fixup_riscv_sub_6b});
|
||||
} else if (isUInt<8>(Value)) {
|
||||
OS << uint8_t(dwarf::DW_CFA_advance_loc1);
|
||||
support::endian::write<uint8_t>(OS, 0, support::little);
|
||||
AddFixups(1, {RISCV::fixup_riscv_set_8, RISCV::fixup_riscv_sub_8});
|
||||
} else if (isUInt<16>(Value)) {
|
||||
OS << uint8_t(dwarf::DW_CFA_advance_loc2);
|
||||
support::endian::write<uint16_t>(OS, 0, support::little);
|
||||
AddFixups(1, {RISCV::fixup_riscv_set_16, RISCV::fixup_riscv_sub_16});
|
||||
} else if (isUInt<32>(Value)) {
|
||||
OS << uint8_t(dwarf::DW_CFA_advance_loc4);
|
||||
support::endian::write<uint32_t>(OS, 0, support::little);
|
||||
AddFixups(1, {RISCV::fixup_riscv_set_32, RISCV::fixup_riscv_sub_32});
|
||||
} else {
|
||||
llvm_unreachable("unsupported CFA encoding");
|
||||
}
|
||||
|
||||
WasRelaxed = OldSize != Data.size();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Given a compressed control flow instruction this function returns
|
||||
// the expanded instruction.
|
||||
unsigned RISCVAsmBackend::getRelaxedOpcode(unsigned Op) const {
|
||||
@ -227,12 +378,25 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
|
||||
case RISCV::fixup_riscv_tls_got_hi20:
|
||||
case RISCV::fixup_riscv_tls_gd_hi20:
|
||||
llvm_unreachable("Relocation should be unconditionally forced\n");
|
||||
case RISCV::fixup_riscv_set_8:
|
||||
case RISCV::fixup_riscv_add_8:
|
||||
case RISCV::fixup_riscv_sub_8:
|
||||
case RISCV::fixup_riscv_set_16:
|
||||
case RISCV::fixup_riscv_add_16:
|
||||
case RISCV::fixup_riscv_sub_16:
|
||||
case RISCV::fixup_riscv_set_32:
|
||||
case RISCV::fixup_riscv_add_32:
|
||||
case RISCV::fixup_riscv_sub_32:
|
||||
case RISCV::fixup_riscv_add_64:
|
||||
case RISCV::fixup_riscv_sub_64:
|
||||
case FK_Data_1:
|
||||
case FK_Data_2:
|
||||
case FK_Data_4:
|
||||
case FK_Data_8:
|
||||
case FK_Data_6b:
|
||||
return Value;
|
||||
case RISCV::fixup_riscv_set_6b:
|
||||
return Value & 0x03;
|
||||
case RISCV::fixup_riscv_lo12_i:
|
||||
case RISCV::fixup_riscv_pcrel_lo12_i:
|
||||
case RISCV::fixup_riscv_tprel_lo12_i:
|
||||
|
@ -42,20 +42,6 @@ public:
|
||||
|
||||
void setForceRelocs() { ForceRelocs = true; }
|
||||
|
||||
// Returns true if relocations will be forced for shouldForceRelocation by
|
||||
// default. This will be true if relaxation is enabled or had previously
|
||||
// been enabled.
|
||||
bool willForceRelocations() const {
|
||||
return ForceRelocs || STI.getFeatureBits()[RISCV::FeatureRelax];
|
||||
}
|
||||
|
||||
// Generate diff expression relocations if the relax feature is enabled or had
|
||||
// previously been enabled, otherwise it is safe for the assembler to
|
||||
// calculate these internally.
|
||||
bool requiresDiffExpressionRelocations() const override {
|
||||
return willForceRelocations();
|
||||
}
|
||||
|
||||
// Return Size with extra Nop Bytes for alignment directive in code section.
|
||||
bool shouldInsertExtraNopBytesForCodeAlign(const MCAlignFragment &AF,
|
||||
unsigned &Size) override;
|
||||
@ -108,6 +94,11 @@ public:
|
||||
void relaxInstruction(MCInst &Inst,
|
||||
const MCSubtargetInfo &STI) const override;
|
||||
|
||||
bool relaxDwarfLineAddr(MCDwarfLineAddrFragment &DF, MCAsmLayout &Layout,
|
||||
bool &WasRelaxed) const override;
|
||||
bool relaxDwarfCFA(MCDwarfCallFrameFragment &DF, MCAsmLayout &Layout,
|
||||
bool &WasRelaxed) const override;
|
||||
|
||||
bool writeNopData(raw_ostream &OS, uint64_t Count) const override;
|
||||
|
||||
const MCTargetOptions &getTargetOptions() const { return TargetOptions; }
|
||||
|
@ -86,6 +86,22 @@ unsigned RISCVELFObjectWriter::getRelocType(MCContext &Ctx,
|
||||
return ELF::R_RISCV_CALL;
|
||||
case RISCV::fixup_riscv_call_plt:
|
||||
return ELF::R_RISCV_CALL_PLT;
|
||||
case RISCV::fixup_riscv_add_8:
|
||||
return ELF::R_RISCV_ADD8;
|
||||
case RISCV::fixup_riscv_sub_8:
|
||||
return ELF::R_RISCV_SUB8;
|
||||
case RISCV::fixup_riscv_add_16:
|
||||
return ELF::R_RISCV_ADD16;
|
||||
case RISCV::fixup_riscv_sub_16:
|
||||
return ELF::R_RISCV_SUB16;
|
||||
case RISCV::fixup_riscv_add_32:
|
||||
return ELF::R_RISCV_ADD32;
|
||||
case RISCV::fixup_riscv_sub_32:
|
||||
return ELF::R_RISCV_SUB32;
|
||||
case RISCV::fixup_riscv_add_64:
|
||||
return ELF::R_RISCV_ADD64;
|
||||
case RISCV::fixup_riscv_sub_64:
|
||||
return ELF::R_RISCV_SUB64;
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,26 +122,6 @@ unsigned RISCVELFObjectWriter::getRelocType(MCContext &Ctx,
|
||||
return ELF::R_RISCV_32;
|
||||
case FK_Data_8:
|
||||
return ELF::R_RISCV_64;
|
||||
case FK_Data_Add_1:
|
||||
return ELF::R_RISCV_ADD8;
|
||||
case FK_Data_Add_2:
|
||||
return ELF::R_RISCV_ADD16;
|
||||
case FK_Data_Add_4:
|
||||
return ELF::R_RISCV_ADD32;
|
||||
case FK_Data_Add_8:
|
||||
return ELF::R_RISCV_ADD64;
|
||||
case FK_Data_Add_6b:
|
||||
return ELF::R_RISCV_SET6;
|
||||
case FK_Data_Sub_1:
|
||||
return ELF::R_RISCV_SUB8;
|
||||
case FK_Data_Sub_2:
|
||||
return ELF::R_RISCV_SUB16;
|
||||
case FK_Data_Sub_4:
|
||||
return ELF::R_RISCV_SUB32;
|
||||
case FK_Data_Sub_8:
|
||||
return ELF::R_RISCV_SUB64;
|
||||
case FK_Data_Sub_6b:
|
||||
return ELF::R_RISCV_SUB6;
|
||||
case RISCV::fixup_riscv_hi20:
|
||||
return ELF::R_RISCV_HI20;
|
||||
case RISCV::fixup_riscv_lo12_i:
|
||||
@ -144,6 +140,32 @@ unsigned RISCVELFObjectWriter::getRelocType(MCContext &Ctx,
|
||||
return ELF::R_RISCV_RELAX;
|
||||
case RISCV::fixup_riscv_align:
|
||||
return ELF::R_RISCV_ALIGN;
|
||||
case RISCV::fixup_riscv_set_6b:
|
||||
return ELF::R_RISCV_SET6;
|
||||
case RISCV::fixup_riscv_sub_6b:
|
||||
return ELF::R_RISCV_SUB6;
|
||||
case RISCV::fixup_riscv_add_8:
|
||||
return ELF::R_RISCV_ADD8;
|
||||
case RISCV::fixup_riscv_set_8:
|
||||
return ELF::R_RISCV_SET8;
|
||||
case RISCV::fixup_riscv_sub_8:
|
||||
return ELF::R_RISCV_SUB8;
|
||||
case RISCV::fixup_riscv_set_16:
|
||||
return ELF::R_RISCV_SET16;
|
||||
case RISCV::fixup_riscv_add_16:
|
||||
return ELF::R_RISCV_ADD16;
|
||||
case RISCV::fixup_riscv_sub_16:
|
||||
return ELF::R_RISCV_SUB16;
|
||||
case RISCV::fixup_riscv_set_32:
|
||||
return ELF::R_RISCV_SET32;
|
||||
case RISCV::fixup_riscv_add_32:
|
||||
return ELF::R_RISCV_ADD32;
|
||||
case RISCV::fixup_riscv_sub_32:
|
||||
return ELF::R_RISCV_SUB32;
|
||||
case RISCV::fixup_riscv_add_64:
|
||||
return ELF::R_RISCV_ADD64;
|
||||
case RISCV::fixup_riscv_sub_64:
|
||||
return ELF::R_RISCV_SUB64;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,9 +15,13 @@
|
||||
#include "RISCVBaseInfo.h"
|
||||
#include "RISCVMCTargetDesc.h"
|
||||
#include "llvm/BinaryFormat/ELF.h"
|
||||
#include "llvm/MC/MCAsmBackend.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"
|
||||
|
||||
@ -167,3 +171,92 @@ size_t RISCVTargetELFStreamer::calculateContentSize() const {
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
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) {
|
||||
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();
|
||||
|
||||
return (A.isInSection() ? A.getSection().hasInstructions()
|
||||
: !A.getName().empty()) ||
|
||||
(B.isInSection() ? B.getSection().hasInstructions()
|
||||
: !B.getName().empty());
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
@ -104,5 +104,11 @@ public:
|
||||
void emitDirectiveOptionRelax() override;
|
||||
void emitDirectiveOptionNoRelax() override;
|
||||
};
|
||||
|
||||
MCELFStreamer *createRISCVELFStreamer(MCContext &C,
|
||||
std::unique_ptr<MCAsmBackend> MAB,
|
||||
std::unique_ptr<MCObjectWriter> MOW,
|
||||
std::unique_ptr<MCCodeEmitter> MCE,
|
||||
bool RelaxAll);
|
||||
}
|
||||
#endif
|
||||
|
@ -68,6 +68,42 @@ enum Fixups {
|
||||
// Used to generate an R_RISCV_ALIGN relocation, which indicates the linker
|
||||
// should fixup the alignment after linker relaxation.
|
||||
fixup_riscv_align,
|
||||
// 8-bit fixup corresponding to R_RISCV_SET8 for local label assignment.
|
||||
fixup_riscv_set_8,
|
||||
// 8-bit fixup corresponding to R_RISCV_ADD8 for 8-bit symbolic difference
|
||||
// paired relocations.
|
||||
fixup_riscv_add_8,
|
||||
// 8-bit fixup corresponding to R_RISCV_SUB8 for 8-bit symbolic difference
|
||||
// paired relocations.
|
||||
fixup_riscv_sub_8,
|
||||
// 16-bit fixup corresponding to R_RISCV_SET16 for local label assignment.
|
||||
fixup_riscv_set_16,
|
||||
// 16-bit fixup corresponding to R_RISCV_ADD16 for 16-bit symbolic difference
|
||||
// paired reloctions.
|
||||
fixup_riscv_add_16,
|
||||
// 16-bit fixup corresponding to R_RISCV_SUB16 for 16-bit symbolic difference
|
||||
// paired reloctions.
|
||||
fixup_riscv_sub_16,
|
||||
// 32-bit fixup corresponding to R_RISCV_SET32 for local label assignment.
|
||||
fixup_riscv_set_32,
|
||||
// 32-bit fixup corresponding to R_RISCV_ADD32 for 32-bit symbolic difference
|
||||
// paired relocations.
|
||||
fixup_riscv_add_32,
|
||||
// 32-bit fixup corresponding to R_RISCV_SUB32 for 32-bit symbolic difference
|
||||
// paired relocations.
|
||||
fixup_riscv_sub_32,
|
||||
// 64-bit fixup corresponding to R_RISCV_ADD64 for 64-bit symbolic difference
|
||||
// paired relocations.
|
||||
fixup_riscv_add_64,
|
||||
// 64-bit fixup corresponding to R_RISCV_SUB64 for 64-bit symbolic difference
|
||||
// paired relocations.
|
||||
fixup_riscv_sub_64,
|
||||
// 6-bit fixup corresponding to R_RISCV_SET6 for local label assignment in
|
||||
// DWARF CFA.
|
||||
fixup_riscv_set_6b,
|
||||
// 6-bit fixup corresponding to R_RISCV_SUB6 for local label assignment in
|
||||
// DWARF CFA.
|
||||
fixup_riscv_sub_6b,
|
||||
|
||||
// Used as a sentinel, must be the last
|
||||
fixup_riscv_invalid,
|
||||
|
@ -92,14 +92,19 @@ const MCFixup *RISCVMCExpr::getPCRelHiFixup(const MCFragment **DFOut) const {
|
||||
bool RISCVMCExpr::evaluateAsRelocatableImpl(MCValue &Res,
|
||||
const MCAsmLayout *Layout,
|
||||
const MCFixup *Fixup) const {
|
||||
if (!getSubExpr()->evaluateAsRelocatable(Res, Layout, Fixup))
|
||||
return false;
|
||||
bool IsSymbolicDifference = false;
|
||||
if (const auto *MBE = dyn_cast<MCBinaryExpr>(getSubExpr())) {
|
||||
if (isa<MCBinaryExpr>(MBE->getLHS()) && isa<MCConstantExpr>(MBE->getRHS()))
|
||||
MBE = cast<MCBinaryExpr>(MBE->getLHS());
|
||||
IsSymbolicDifference = isa<MCSymbolRefExpr>(MBE->getLHS()) &&
|
||||
isa<MCSymbolRefExpr>(MBE->getRHS());
|
||||
}
|
||||
|
||||
// Some custom fixup types are not valid with symbol difference expressions
|
||||
if (Res.getSymA() && Res.getSymB()) {
|
||||
if (IsSymbolicDifference) {
|
||||
switch (getKind()) {
|
||||
default:
|
||||
return true;
|
||||
break;
|
||||
case VK_RISCV_LO:
|
||||
case VK_RISCV_HI:
|
||||
case VK_RISCV_PCREL_LO:
|
||||
@ -113,8 +118,7 @@ bool RISCVMCExpr::evaluateAsRelocatableImpl(MCValue &Res,
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return getSubExpr()->evaluateAsRelocatable(Res, Layout, Fixup);
|
||||
}
|
||||
|
||||
void RISCVMCExpr::visitUsedExpr(MCStreamer &Streamer) const {
|
||||
|
@ -18,9 +18,12 @@
|
||||
#include "RISCVTargetStreamer.h"
|
||||
#include "TargetInfo/RISCVTargetInfo.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/MC/MCAsmBackend.h"
|
||||
#include "llvm/MC/MCAsmInfo.h"
|
||||
#include "llvm/MC/MCCodeEmitter.h"
|
||||
#include "llvm/MC/MCInstrAnalysis.h"
|
||||
#include "llvm/MC/MCInstrInfo.h"
|
||||
#include "llvm/MC/MCObjectWriter.h"
|
||||
#include "llvm/MC/MCRegisterInfo.h"
|
||||
#include "llvm/MC/MCStreamer.h"
|
||||
#include "llvm/MC/MCSubtargetInfo.h"
|
||||
@ -138,6 +141,17 @@ static MCInstrAnalysis *createRISCVInstrAnalysis(const MCInstrInfo *Info) {
|
||||
return new RISCVMCInstrAnalysis(Info);
|
||||
}
|
||||
|
||||
namespace {
|
||||
MCStreamer *createRISCVELFStreamer(const Triple &T, MCContext &Context,
|
||||
std::unique_ptr<MCAsmBackend> &&MAB,
|
||||
std::unique_ptr<MCObjectWriter> &&MOW,
|
||||
std::unique_ptr<MCCodeEmitter> &&MCE,
|
||||
bool RelaxAll) {
|
||||
return createRISCVELFStreamer(Context, std::move(MAB), std::move(MOW),
|
||||
std::move(MCE), RelaxAll);
|
||||
}
|
||||
} // end anonymous namespace
|
||||
|
||||
extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTargetMC() {
|
||||
for (Target *T : {&getTheRISCV32Target(), &getTheRISCV64Target()}) {
|
||||
TargetRegistry::RegisterMCAsmInfo(*T, createRISCVMCAsmInfo);
|
||||
@ -147,6 +161,7 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTargetMC() {
|
||||
TargetRegistry::RegisterMCCodeEmitter(*T, createRISCVMCCodeEmitter);
|
||||
TargetRegistry::RegisterMCInstPrinter(*T, createRISCVMCInstPrinter);
|
||||
TargetRegistry::RegisterMCSubtargetInfo(*T, createRISCVMCSubtargetInfo);
|
||||
TargetRegistry::RegisterELFStreamer(*T, createRISCVELFStreamer);
|
||||
TargetRegistry::RegisterObjectTargetStreamer(
|
||||
*T, createRISCVObjectTargetStreamer);
|
||||
TargetRegistry::RegisterMCInstrAnalysis(*T, createRISCVInstrAnalysis);
|
||||
|
@ -1,10 +1,10 @@
|
||||
; RUN: llc -filetype=obj -mtriple=riscv32 -mattr=+relax %s -o - \
|
||||
; RUN: | llvm-readobj -r - | FileCheck -check-prefix=RELAX %s
|
||||
; RUN: | llvm-readobj -r - | FileCheck %s
|
||||
; RUN: llc -filetype=obj -mtriple=riscv32 -mattr=-relax %s -o - \
|
||||
; RUN: | llvm-readobj -r - | FileCheck -check-prefix=NORELAX %s
|
||||
; RUN: | llvm-readobj -r - | FileCheck %s
|
||||
|
||||
; Check that a difference between two symbols in the same fragment
|
||||
; causes relocations to be emitted if and only if relaxation is enabled.
|
||||
; causes relocations to be emitted.
|
||||
;
|
||||
; This specific test is checking that the size of the function in
|
||||
; the debug information is represented by a relocation. This isn't
|
||||
@ -22,11 +22,18 @@ entry:
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
; RELAX: 0x22 R_RISCV_ADD32 - 0x0
|
||||
; RELAX: 0x22 R_RISCV_SUB32 - 0x0
|
||||
; RELAX: 0x2B R_RISCV_ADD32 - 0x0
|
||||
; RELAX: 0x2B R_RISCV_SUB32 - 0x0
|
||||
; NORELAX-NOT: R_RISCV_ADD32
|
||||
; CHECK: Section {{.*}} .rela.debug_info {
|
||||
; CHECK: 0x22 R_RISCV_ADD32 - 0x0
|
||||
; CHECK-NEXT: 0x22 R_RISCV_SUB32 - 0x0
|
||||
; CHECK: 0x2B R_RISCV_ADD32 - 0x0
|
||||
; CHECK-NEXT: 0x2B R_RISCV_SUB32 - 0x0
|
||||
; CHECK: }
|
||||
|
||||
; CHECK: Section {{.*}} .rela.eh_frame {
|
||||
; CHECK: 0x1C R_RISCV_32_PCREL - 0x0
|
||||
; CHECK: 0x20 R_RISCV_ADD32 - 0x0
|
||||
; CHECK-NEXT: 0x20 R_RISCV_SUB32 - 0x0
|
||||
; CHECK: }
|
||||
|
||||
!llvm.dbg.cu = !{!0}
|
||||
!llvm.module.flags = !{!3, !4, !5}
|
||||
|
@ -1,12 +1,11 @@
|
||||
; RUN: llc -filetype=obj -mtriple=riscv32 -mattr=+relax %s -o - \
|
||||
; RUN: | llvm-readobj -r - | FileCheck -check-prefix=RELAX %s
|
||||
; RUN: llc -filetype=obj -mtriple=riscv32 -mattr=-relax %s -o - \
|
||||
; RUN: | llvm-readobj -r - | FileCheck -check-prefix=NORELAX %s
|
||||
; RUN: | llvm-readobj -r - | FileCheck -check-prefix=RELAX %s
|
||||
|
||||
; This test checks that a diff inserted via inline assembly only causes
|
||||
; relocations when relaxation is enabled. This isn't an assembly test
|
||||
; as the assembler takes a different path through LLVM, which is
|
||||
; already covered by the fixups-expr.s test.
|
||||
; This test checks that a diff inserted via inline assembly always causes
|
||||
; relocations. This isn't an assembly test as the assembler takes a different
|
||||
; path through LLVM, which is already covered by the fixups-expr.s test.
|
||||
|
||||
define i32 @main() nounwind {
|
||||
entry:
|
||||
@ -14,7 +13,6 @@ entry:
|
||||
store i32 0, i32* %retval, align 4
|
||||
; RELAX: R_RISCV_ADD64 b
|
||||
; RELAX: R_RISCV_SUB64 a
|
||||
; NORELAX-NOT: R_RISCV_ADD
|
||||
call void asm sideeffect "a:\0Ab:\0A.dword b-a", ""()
|
||||
ret i32 0
|
||||
}
|
||||
|
@ -1,19 +1,18 @@
|
||||
# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+relax < %s \
|
||||
# RUN: | llvm-readobj -r - | FileCheck -check-prefix=RELAX-RELOC %s
|
||||
# RUN: | llvm-readobj -r - | FileCheck %s
|
||||
# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=-relax < %s \
|
||||
# RUN: | llvm-readobj -r - | FileCheck -check-prefix=NORELAX-RELOC %s
|
||||
# RUN: | llvm-readobj -r - | FileCheck %s
|
||||
|
||||
# Ensure that the eh_frame records the symbolic difference with the paired
|
||||
# relocations always.
|
||||
|
||||
func:
|
||||
.cfi_startproc
|
||||
ret
|
||||
.cfi_endproc
|
||||
|
||||
# RELAX-RELOC: Section (4) .rela.eh_frame {
|
||||
# RELAX-RELOC-NEXT: 0x1C R_RISCV_32_PCREL - 0x0
|
||||
# RELAX-RELOC-NEXT: 0x20 R_RISCV_ADD32 - 0x0
|
||||
# RELAX-RELOC-NEXT: 0x20 R_RISCV_SUB32 - 0x0
|
||||
# RELAX-RELOC-NEXT: }
|
||||
|
||||
# NORELAX-RELOC: Section (4) .rela.eh_frame {
|
||||
# NORELAX-RELOC-NEXT: 0x1C R_RISCV_32_PCREL - 0x0
|
||||
# NORELAX-RELOC-NEXT: }
|
||||
# CHECK: Section (4) .rela.eh_frame {
|
||||
# CHECK-NEXT: 0x1C R_RISCV_32_PCREL - 0x0
|
||||
# CHECK-NEXT: 0x20 R_RISCV_ADD32 - 0x0
|
||||
# CHECK-NEXT: 0x20 R_RISCV_SUB32 - 0x0
|
||||
# CHECK-NEXT: }
|
||||
|
@ -1,15 +1,14 @@
|
||||
# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+relax %s \
|
||||
# RUN: | llvm-readobj -r - | FileCheck -check-prefix=RELAX %s
|
||||
# RUN: | llvm-readobj -r - | FileCheck -check-prefix RELAX %s
|
||||
# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=-relax %s \
|
||||
# RUN: | llvm-readobj -r - | FileCheck -check-prefix=NORELAX %s
|
||||
# RUN: | llvm-readobj -r - | FileCheck -check-prefix RELAX %s
|
||||
|
||||
# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax %s \
|
||||
# RUN: | llvm-readobj -r - | FileCheck -check-prefix=RELAX %s
|
||||
# RUN: | llvm-readobj -r - | FileCheck -check-prefix RELAX %s
|
||||
# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=-relax %s \
|
||||
# RUN: | llvm-readobj -r - | FileCheck -check-prefix=NORELAX %s
|
||||
# RUN: | llvm-readobj -r - | FileCheck -check-prefix RELAX %s
|
||||
|
||||
# Check that subtraction expressions are emitted as two relocations
|
||||
# only when relaxation is enabled
|
||||
# Check that subtraction expressions are emitted as two relocations always.
|
||||
|
||||
.globl G1
|
||||
.globl G2
|
||||
@ -44,4 +43,3 @@ G2:
|
||||
# RELAX: 0x1C R_RISCV_SUB8 .L1 0x0
|
||||
# RELAX: 0x1D R_RISCV_ADD8 G2 0x0
|
||||
# RELAX: 0x1D R_RISCV_SUB8 G1 0x0
|
||||
# NORELAX-NOT: R_RISCV
|
||||
|
@ -1,9 +1,5 @@
|
||||
# RUN: not llvm-mc -filetype=obj -triple=riscv32 -mattr=+relax %s 2>&1 \
|
||||
# RUN: | FileCheck %s -check-prefix=CHECK-RELAX
|
||||
# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=-relax %s 2>&1 \
|
||||
# RUN: | llvm-objdump -d - | FileCheck %s --check-prefix=CHECK-INSTR
|
||||
# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=-relax %s 2>&1 \
|
||||
# RUN: | llvm-objdump -r - | FileCheck %s --check-prefix=CHECK-REL
|
||||
# RUN: not llvm-mc -filetype=obj -triple=riscv32 -mattr=+relax %s 2>&1 | FileCheck %s
|
||||
# RUN: not llvm-mc -filetype=obj -triple=riscv32 -mattr=-relax %s 2>&1 | FileCheck %s
|
||||
|
||||
# Check the assembler rejects hi and lo expressions with constant expressions
|
||||
# involving labels when diff expressions are emitted as relocation pairs.
|
||||
@ -13,19 +9,13 @@ tmp1:
|
||||
# Emit zeros so that difference between tmp1 and tmp3 is 0x30124 bytes.
|
||||
.fill 0x30124-8
|
||||
tmp2:
|
||||
# CHECK-RELAX: :[[@LINE+1]]:{{[0-9]+}}: error: expected relocatable expression
|
||||
# CHECK: :[[#@LINE+1]]:[[#]]: error: expected relocatable expression
|
||||
lui t0, %hi(tmp3-tmp1)
|
||||
# CHECK-RELAX: :[[@LINE+1]]:{{[0-9]+}}: error: expected relocatable expression
|
||||
# CHECK: :[[#@LINE+1]]:[[#]]: error: expected relocatable expression
|
||||
lw ra, %lo(tmp3-tmp1)(t0)
|
||||
# CHECK-INSTR: lui t0, 48
|
||||
# CHECK-INSTR: lw ra, 292(t0)
|
||||
|
||||
tmp3:
|
||||
# CHECK-RELAX: :[[@LINE+1]]:{{[0-9]+}}: error: expected relocatable expression
|
||||
# CHECK: :[[#@LINE+1]]:[[#]]: error: expected relocatable expression
|
||||
lui t1, %hi(tmp2-tmp3)
|
||||
# CHECK-RELAX: :[[@LINE+1]]:{{[0-9]+}}: error: expected relocatable expression
|
||||
# CHECK: :[[#@LINE+1]]:[[#]]: error: expected relocatable expression
|
||||
lw sp, %lo(tmp2-tmp3)(t1)
|
||||
# CHECK-INSTR: lui t1, 0
|
||||
# CHECK-INSTR: lw sp, -8(t1)
|
||||
|
||||
# CHECK-REL-NOT: R_RISCV
|
11
test/MC/RISCV/reloc-addend.s
Normal file
11
test/MC/RISCV/reloc-addend.s
Normal file
@ -0,0 +1,11 @@
|
||||
# RUN: llvm-mc -triple riscv64 -filetype obj -o - %s | llvm-readobj -r - | FileCheck %s
|
||||
|
||||
.section __jump_table,"aw",@progbits
|
||||
.p2align 3
|
||||
.Ltmp0:
|
||||
.quad (function+128)-.Ltmp0
|
||||
|
||||
# CHECK: .rela__jump_table {
|
||||
# CHECK: 0x0 R_RISCV_ADD64 function 0x80
|
||||
# CHECK-NEXT: 0x0 R_RISCV_SUB64 .Ltmp0 0x0
|
||||
# CHECK: }
|
34
test/MC/RISCV/scoped-relaxation.s
Normal file
34
test/MC/RISCV/scoped-relaxation.s
Normal file
@ -0,0 +1,34 @@
|
||||
# RUN: llvm-mc -mattr -relax -triple riscv64 -filetype obj %s -o - | llvm-readobj -d -r - | FileCheck %s
|
||||
|
||||
.global function
|
||||
|
||||
# CHECK: .rela.text {
|
||||
|
||||
# Unrelaxed reference, this would normally fail, but the subsequent scoped
|
||||
# relaxation forces relaxation on the file.
|
||||
.dword function - .
|
||||
|
||||
# CHECK: 0x0 R_RISCV_ADD64 function 0x0
|
||||
# CHECK-NEXT: 0x0 R_RISCV_SUB64 - 0x0
|
||||
|
||||
# Relaxed reference, this will resolve to a pair of `RISCV_ADD64` and
|
||||
# `RISCV_SUB64` relocation.
|
||||
.option push
|
||||
.option relax
|
||||
.dword function - .
|
||||
.option pop
|
||||
|
||||
# CHECK: 0x8 R_RISCV_ADD64 function 0x0
|
||||
# CHECK-NEXT: 0x8 R_RISCV_SUB64 - 0x0
|
||||
|
||||
# Unrelaxed reference, this will resolve to a pair of `RISCV_ADD64` and
|
||||
# `RISCV_SUB64` relocation due to relaxation being sticky to the file.
|
||||
.option push
|
||||
.option norelax
|
||||
.dword function - .
|
||||
.option pop
|
||||
|
||||
# CHECK: 0x10 R_RISCV_ADD64 function 0x0
|
||||
# CHECK-NEXT: 0x10 R_RISCV_SUB64 - 0x0
|
||||
|
||||
# CHECK: }
|
Loading…
Reference in New Issue
Block a user