1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-25 20:23:11 +01:00
llvm-mirror/include/llvm/MC/MCAsmBackend.h
Saleem Abdulrasool f56e4f6d3d 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
2021-06-17 08:20:02 -07:00

218 lines
8.4 KiB
C++

//===- llvm/MC/MCAsmBackend.h - MC Asm Backend ------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_MC_MCASMBACKEND_H
#define LLVM_MC_MCASMBACKEND_H
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h"
#include "llvm/MC/MCDirectives.h"
#include "llvm/MC/MCFixup.h"
#include "llvm/MC/MCFragment.h"
#include "llvm/Support/Endian.h"
#include <cstdint>
namespace llvm {
class MCAsmLayout;
class MCAssembler;
class MCCFIInstruction;
struct MCFixupKindInfo;
class MCInst;
class MCObjectStreamer;
class MCObjectTargetWriter;
class MCObjectWriter;
class MCSubtargetInfo;
class MCValue;
class raw_pwrite_stream;
class StringRef;
/// Generic interface to target specific assembler backends.
class MCAsmBackend {
protected: // Can only create subclasses.
MCAsmBackend(support::endianness Endian);
public:
MCAsmBackend(const MCAsmBackend &) = delete;
MCAsmBackend &operator=(const MCAsmBackend &) = delete;
virtual ~MCAsmBackend();
const support::endianness Endian;
/// Return true if this target might automatically pad instructions and thus
/// need to emit padding enable/disable directives around sensative code.
virtual bool allowAutoPadding() const { return false; }
/// Return true if this target allows an unrelaxable instruction to be
/// emitted into RelaxableFragment and then we can increase its size in a
/// tricky way for optimization.
virtual bool allowEnhancedRelaxation() const { return false; }
/// Give the target a chance to manipulate state related to instruction
/// alignment (e.g. padding for optimization), instruction relaxablility, etc.
/// before and after actually emitting the instruction.
virtual void emitInstructionBegin(MCObjectStreamer &OS, const MCInst &Inst) {}
virtual void emitInstructionEnd(MCObjectStreamer &OS, const MCInst &Inst) {}
/// lifetime management
virtual void reset() {}
/// Create a new MCObjectWriter instance for use by the assembler backend to
/// emit the final object file.
std::unique_ptr<MCObjectWriter>
createObjectWriter(raw_pwrite_stream &OS) const;
/// Create an MCObjectWriter that writes two object files: a .o file which is
/// linked into the final program and a .dwo file which is used by debuggers.
/// This function is only supported with ELF targets.
std::unique_ptr<MCObjectWriter>
createDwoObjectWriter(raw_pwrite_stream &OS, raw_pwrite_stream &DwoOS) const;
virtual std::unique_ptr<MCObjectTargetWriter>
createObjectTargetWriter() const = 0;
/// \name Target Fixup Interfaces
/// @{
/// Get the number of target specific fixup kinds.
virtual unsigned getNumFixupKinds() const = 0;
/// Map a relocation name used in .reloc to a fixup kind.
virtual Optional<MCFixupKind> getFixupKind(StringRef Name) const;
/// Get information on a fixup kind.
virtual const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const;
/// Hook to check if a relocation is needed for some target specific reason.
virtual bool shouldForceRelocation(const MCAssembler &Asm,
const MCFixup &Fixup,
const MCValue &Target) {
return false;
}
/// Hook to check if extra nop bytes must be inserted for alignment directive.
/// For some targets this may be necessary in order to support linker
/// relaxation. The number of bytes to insert are returned in Size.
virtual bool shouldInsertExtraNopBytesForCodeAlign(const MCAlignFragment &AF,
unsigned &Size) {
return false;
}
/// Hook which indicates if the target requires a fixup to be generated when
/// handling an align directive in an executable section
virtual bool shouldInsertFixupForCodeAlign(MCAssembler &Asm,
const MCAsmLayout &Layout,
MCAlignFragment &AF) {
return false;
}
virtual bool evaluateTargetFixup(const MCAssembler &Asm,
const MCAsmLayout &Layout,
const MCFixup &Fixup, const MCFragment *DF,
const MCValue &Target, uint64_t &Value,
bool &WasForced) {
llvm_unreachable("Need to implement hook if target has custom fixups");
}
/// Apply the \p Value for given \p Fixup into the provided data fragment, at
/// the offset specified by the fixup and following the fixup kind as
/// appropriate. Errors (such as an out of range fixup value) should be
/// reported via \p Ctx.
/// The \p STI is present only for fragments of type MCRelaxableFragment and
/// MCDataFragment with hasInstructions() == true.
virtual void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
const MCValue &Target, MutableArrayRef<char> Data,
uint64_t Value, bool IsResolved,
const MCSubtargetInfo *STI) const = 0;
/// @}
/// \name Target Relaxation Interfaces
/// @{
/// Check whether the given instruction may need relaxation.
///
/// \param Inst - The instruction to test.
/// \param STI - The MCSubtargetInfo in effect when the instruction was
/// encoded.
virtual bool mayNeedRelaxation(const MCInst &Inst,
const MCSubtargetInfo &STI) const {
return false;
}
/// Target specific predicate for whether a given fixup requires the
/// associated instruction to be relaxed.
virtual bool fixupNeedsRelaxationAdvanced(const MCFixup &Fixup, bool Resolved,
uint64_t Value,
const MCRelaxableFragment *DF,
const MCAsmLayout &Layout,
const bool WasForced) const;
/// Simple predicate for targets where !Resolved implies requiring relaxation
virtual bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
const MCRelaxableFragment *DF,
const MCAsmLayout &Layout) const = 0;
/// Relax the instruction in the given fragment to the next wider instruction.
///
/// \param [out] Inst The instruction to relax, which is also the relaxed
/// instruction.
/// \param STI the subtarget information for the associated instruction.
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
/// will use this to emit excess padding in situations where the padding
/// required for simple alignment would be less than the minimum nop size.
///
virtual unsigned getMinimumNopSize() const { return 1; }
/// Returns the maximum size of a nop in bytes on this target.
///
virtual unsigned getMaximumNopSize() const { return 0; }
/// Write an (optimal) nop sequence of Count bytes to the given output. If the
/// target cannot generate such a sequence, it should return an error.
///
/// \return - True on success.
virtual bool writeNopData(raw_ostream &OS, uint64_t Count) const = 0;
/// Give backend an opportunity to finish layout after relaxation
virtual void finishLayout(MCAssembler const &Asm,
MCAsmLayout &Layout) const {}
/// Handle any target-specific assembler flags. By default, do nothing.
virtual void handleAssemblerFlag(MCAssemblerFlag Flag) {}
/// Generate the compact unwind encoding for the CFI instructions.
virtual uint32_t
generateCompactUnwindEncoding(ArrayRef<MCCFIInstruction>) const {
return 0;
}
/// Check whether a given symbol has been flagged with MICROMIPS flag.
virtual bool isMicroMips(const MCSymbol *Sym) const {
return false;
}
};
} // end namespace llvm
#endif // LLVM_MC_MCASMBACKEND_H