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
176 lines
5.9 KiB
C++
176 lines
5.9 KiB
C++
//===-- RISCVELFObjectWriter.cpp - RISCV ELF Writer -----------------------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "MCTargetDesc/RISCVFixupKinds.h"
|
|
#include "MCTargetDesc/RISCVMCExpr.h"
|
|
#include "MCTargetDesc/RISCVMCTargetDesc.h"
|
|
#include "llvm/MC/MCContext.h"
|
|
#include "llvm/MC/MCELFObjectWriter.h"
|
|
#include "llvm/MC/MCFixup.h"
|
|
#include "llvm/MC/MCObjectWriter.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
|
|
using namespace llvm;
|
|
|
|
namespace {
|
|
class RISCVELFObjectWriter : public MCELFObjectTargetWriter {
|
|
public:
|
|
RISCVELFObjectWriter(uint8_t OSABI, bool Is64Bit);
|
|
|
|
~RISCVELFObjectWriter() override;
|
|
|
|
// Return true if the given relocation must be with a symbol rather than
|
|
// section plus offset.
|
|
bool needsRelocateWithSymbol(const MCSymbol &Sym,
|
|
unsigned Type) const override {
|
|
// TODO: this is very conservative, update once RISC-V psABI requirements
|
|
// are clarified.
|
|
return true;
|
|
}
|
|
|
|
protected:
|
|
unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
|
|
const MCFixup &Fixup, bool IsPCRel) const override;
|
|
};
|
|
}
|
|
|
|
RISCVELFObjectWriter::RISCVELFObjectWriter(uint8_t OSABI, bool Is64Bit)
|
|
: MCELFObjectTargetWriter(Is64Bit, OSABI, ELF::EM_RISCV,
|
|
/*HasRelocationAddend*/ true) {}
|
|
|
|
RISCVELFObjectWriter::~RISCVELFObjectWriter() {}
|
|
|
|
unsigned RISCVELFObjectWriter::getRelocType(MCContext &Ctx,
|
|
const MCValue &Target,
|
|
const MCFixup &Fixup,
|
|
bool IsPCRel) const {
|
|
const MCExpr *Expr = Fixup.getValue();
|
|
// Determine the type of the relocation
|
|
unsigned Kind = Fixup.getTargetKind();
|
|
if (Kind >= FirstLiteralRelocationKind)
|
|
return Kind - FirstLiteralRelocationKind;
|
|
if (IsPCRel) {
|
|
switch (Kind) {
|
|
default:
|
|
Ctx.reportError(Fixup.getLoc(), "Unsupported relocation type");
|
|
return ELF::R_RISCV_NONE;
|
|
case FK_Data_4:
|
|
case FK_PCRel_4:
|
|
return ELF::R_RISCV_32_PCREL;
|
|
case RISCV::fixup_riscv_pcrel_hi20:
|
|
return ELF::R_RISCV_PCREL_HI20;
|
|
case RISCV::fixup_riscv_pcrel_lo12_i:
|
|
return ELF::R_RISCV_PCREL_LO12_I;
|
|
case RISCV::fixup_riscv_pcrel_lo12_s:
|
|
return ELF::R_RISCV_PCREL_LO12_S;
|
|
case RISCV::fixup_riscv_got_hi20:
|
|
return ELF::R_RISCV_GOT_HI20;
|
|
case RISCV::fixup_riscv_tls_got_hi20:
|
|
return ELF::R_RISCV_TLS_GOT_HI20;
|
|
case RISCV::fixup_riscv_tls_gd_hi20:
|
|
return ELF::R_RISCV_TLS_GD_HI20;
|
|
case RISCV::fixup_riscv_jal:
|
|
return ELF::R_RISCV_JAL;
|
|
case RISCV::fixup_riscv_branch:
|
|
return ELF::R_RISCV_BRANCH;
|
|
case RISCV::fixup_riscv_rvc_jump:
|
|
return ELF::R_RISCV_RVC_JUMP;
|
|
case RISCV::fixup_riscv_rvc_branch:
|
|
return ELF::R_RISCV_RVC_BRANCH;
|
|
case RISCV::fixup_riscv_call:
|
|
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;
|
|
}
|
|
}
|
|
|
|
switch (Kind) {
|
|
default:
|
|
Ctx.reportError(Fixup.getLoc(), "Unsupported relocation type");
|
|
return ELF::R_RISCV_NONE;
|
|
case FK_Data_1:
|
|
Ctx.reportError(Fixup.getLoc(), "1-byte data relocations not supported");
|
|
return ELF::R_RISCV_NONE;
|
|
case FK_Data_2:
|
|
Ctx.reportError(Fixup.getLoc(), "2-byte data relocations not supported");
|
|
return ELF::R_RISCV_NONE;
|
|
case FK_Data_4:
|
|
if (Expr->getKind() == MCExpr::Target &&
|
|
cast<RISCVMCExpr>(Expr)->getKind() == RISCVMCExpr::VK_RISCV_32_PCREL)
|
|
return ELF::R_RISCV_32_PCREL;
|
|
return ELF::R_RISCV_32;
|
|
case FK_Data_8:
|
|
return ELF::R_RISCV_64;
|
|
case RISCV::fixup_riscv_hi20:
|
|
return ELF::R_RISCV_HI20;
|
|
case RISCV::fixup_riscv_lo12_i:
|
|
return ELF::R_RISCV_LO12_I;
|
|
case RISCV::fixup_riscv_lo12_s:
|
|
return ELF::R_RISCV_LO12_S;
|
|
case RISCV::fixup_riscv_tprel_hi20:
|
|
return ELF::R_RISCV_TPREL_HI20;
|
|
case RISCV::fixup_riscv_tprel_lo12_i:
|
|
return ELF::R_RISCV_TPREL_LO12_I;
|
|
case RISCV::fixup_riscv_tprel_lo12_s:
|
|
return ELF::R_RISCV_TPREL_LO12_S;
|
|
case RISCV::fixup_riscv_tprel_add:
|
|
return ELF::R_RISCV_TPREL_ADD;
|
|
case RISCV::fixup_riscv_relax:
|
|
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;
|
|
}
|
|
}
|
|
|
|
std::unique_ptr<MCObjectTargetWriter>
|
|
llvm::createRISCVELFObjectWriter(uint8_t OSABI, bool Is64Bit) {
|
|
return std::make_unique<RISCVELFObjectWriter>(OSABI, Is64Bit);
|
|
}
|