1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 18:54:02 +01:00
llvm-mirror/include/llvm/MC/MCFixup.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

149 lines
5.3 KiB
C++

//===-- llvm/MC/MCFixup.h - Instruction Relocation and Patching -*- 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_MCFIXUP_H
#define LLVM_MC_MCFIXUP_H
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/SMLoc.h"
#include <cassert>
namespace llvm {
class MCExpr;
/// Extensible enumeration to represent the type of a fixup.
enum MCFixupKind {
FK_NONE = 0, ///< A no-op fixup.
FK_Data_1, ///< A one-byte fixup.
FK_Data_2, ///< A two-byte fixup.
FK_Data_4, ///< A four-byte fixup.
FK_Data_8, ///< A eight-byte fixup.
FK_Data_6b, ///< A six-bits fixup.
FK_PCRel_1, ///< A one-byte pc relative fixup.
FK_PCRel_2, ///< A two-byte pc relative fixup.
FK_PCRel_4, ///< A four-byte pc relative fixup.
FK_PCRel_8, ///< A eight-byte pc relative fixup.
FK_GPRel_1, ///< A one-byte gp relative fixup.
FK_GPRel_2, ///< A two-byte gp relative fixup.
FK_GPRel_4, ///< A four-byte gp relative fixup.
FK_GPRel_8, ///< A eight-byte gp relative fixup.
FK_DTPRel_4, ///< A four-byte dtp relative fixup.
FK_DTPRel_8, ///< A eight-byte dtp relative fixup.
FK_TPRel_4, ///< A four-byte tp relative fixup.
FK_TPRel_8, ///< A eight-byte tp relative fixup.
FK_SecRel_1, ///< A one-byte section relative fixup.
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.
FirstTargetFixupKind = 128,
/// The range [FirstLiteralRelocationKind, MaxTargetFixupKind) is used for
/// relocations coming from .reloc directive. Fixup kind
/// FirstLiteralRelocationKind+V represents the relocation type with number V.
FirstLiteralRelocationKind = 256,
/// Set limit to accommodate the highest reloc type in use for all Targets,
/// currently R_AARCH64_IRELATIVE at 1032, including room for expansion.
MaxFixupKind = FirstLiteralRelocationKind + 1032 + 32,
};
/// Encode information on a single operation to perform on a byte
/// sequence (e.g., an encoded instruction) which requires assemble- or run-
/// time patching.
///
/// Fixups are used any time the target instruction encoder needs to represent
/// some value in an instruction which is not yet concrete. The encoder will
/// encode the instruction assuming the value is 0, and emit a fixup which
/// communicates to the assembler backend how it should rewrite the encoded
/// value.
///
/// During the process of relaxation, the assembler will apply fixups as
/// symbolic values become concrete. When relaxation is complete, any remaining
/// fixups become relocations in the object file (or errors, if the fixup cannot
/// be encoded on the target).
class MCFixup {
/// The value to put into the fixup location. The exact interpretation of the
/// expression is target dependent, usually it will be one of the operands to
/// an instruction or an assembler directive.
const MCExpr *Value = nullptr;
/// The byte index of start of the relocation inside the MCFragment.
uint32_t Offset = 0;
/// The target dependent kind of fixup item this is. The kind is used to
/// determine how the operand value should be encoded into the instruction.
MCFixupKind Kind = FK_NONE;
/// The source location which gave rise to the fixup, if any.
SMLoc Loc;
public:
static MCFixup create(uint32_t Offset, const MCExpr *Value,
MCFixupKind Kind, SMLoc Loc = SMLoc()) {
assert(Kind <= MaxFixupKind && "Kind out of range!");
MCFixup FI;
FI.Value = Value;
FI.Offset = Offset;
FI.Kind = Kind;
FI.Loc = Loc;
return FI;
}
MCFixupKind getKind() const { return Kind; }
unsigned getTargetKind() const { return Kind; }
uint32_t getOffset() const { return Offset; }
void setOffset(uint32_t Value) { Offset = Value; }
const MCExpr *getValue() const { return Value; }
/// Return the generic fixup kind for a value with the given size. It
/// is an error to pass an unsupported size.
static MCFixupKind getKindForSize(unsigned Size, bool IsPCRel) {
switch (Size) {
default: llvm_unreachable("Invalid generic fixup size!");
case 1:
return IsPCRel ? FK_PCRel_1 : FK_Data_1;
case 2:
return IsPCRel ? FK_PCRel_2 : FK_Data_2;
case 4:
return IsPCRel ? FK_PCRel_4 : FK_Data_4;
case 8:
return IsPCRel ? FK_PCRel_8 : FK_Data_8;
}
}
/// Return the generic fixup kind for a value with the given size in bits.
/// It is an error to pass an unsupported size.
static MCFixupKind getKindForSizeInBits(unsigned Size, bool IsPCRel) {
switch (Size) {
default:
llvm_unreachable("Invalid generic fixup size!");
case 6:
assert(!IsPCRel && "Invalid pc-relative fixup size!");
return FK_Data_6b;
case 8:
return IsPCRel ? FK_PCRel_1 : FK_Data_1;
case 16:
return IsPCRel ? FK_PCRel_2 : FK_Data_2;
case 32:
return IsPCRel ? FK_PCRel_4 : FK_Data_4;
case 64:
return IsPCRel ? FK_PCRel_8 : FK_Data_8;
}
}
SMLoc getLoc() const { return Loc; }
};
} // End llvm namespace
#endif