1
0
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:
Saleem Abdulrasool 2021-05-26 15:41:11 +00:00
parent 84970078e4
commit f56e4f6d3d
23 changed files with 502 additions and 350 deletions

View File

@ -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

View File

@ -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

View File

@ -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; }
};

View File

@ -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];

View File

@ -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*/)));
}
MCDwarfLineAddr::Encode(Context, getDWARFLinetableParams(), LineDelta,
AddrDelta, OSE);
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);
}
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();

View File

@ -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;
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);
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);
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);
support::endian::write<uint32_t>(OS, AddrDelta, E);
}
}

View File

@ -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).

View File

@ -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);
}

View File

@ -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:

View File

@ -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; }

View File

@ -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;
}
}

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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 {

View File

@ -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);

View File

@ -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}

View File

@ -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
}

View File

@ -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: }

View File

@ -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

View File

@ -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

View 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: }

View 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: }