Summary: Change VEAsmParser to support identification with relocation information in assmebler. Change VEAsmBackend to support relocation information in MC layer. Change VEDisassembler and VEMCCodeEmitter to support binary generation of branch target operands. Add REFLONG fixup and variant kind to support new R_VE_REFLONG ELF symbol. And, add regression test in both MC and CodeGen to check binary genaration with relocation information. Differential Revision: https://reviews.llvm.org/D81553
226 lines
5.8 KiB
C++
226 lines
5.8 KiB
C++
//===-- VEMCExpr.cpp - VE specific MC expression classes ------------------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file contains the implementation of the assembly expression modifiers
|
|
// accepted by the VE architecture (e.g. "%hi", "%lo", ...).
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "VEMCExpr.h"
|
|
#include "llvm/MC/MCAssembler.h"
|
|
#include "llvm/MC/MCContext.h"
|
|
#include "llvm/MC/MCObjectStreamer.h"
|
|
#include "llvm/MC/MCSymbolELF.h"
|
|
#include "llvm/BinaryFormat/ELF.h"
|
|
|
|
using namespace llvm;
|
|
|
|
#define DEBUG_TYPE "vemcexpr"
|
|
|
|
const VEMCExpr *VEMCExpr::create(VariantKind Kind, const MCExpr *Expr,
|
|
MCContext &Ctx) {
|
|
return new (Ctx) VEMCExpr(Kind, Expr);
|
|
}
|
|
|
|
void VEMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const {
|
|
|
|
bool closeParen = printVariantKind(OS, Kind);
|
|
|
|
const MCExpr *Expr = getSubExpr();
|
|
Expr->print(OS, MAI);
|
|
|
|
if (closeParen)
|
|
OS << ')';
|
|
printVariantKindSuffix(OS, Kind);
|
|
}
|
|
|
|
bool VEMCExpr::printVariantKind(raw_ostream &OS, VariantKind Kind) {
|
|
switch (Kind) {
|
|
case VK_VE_None:
|
|
case VK_VE_REFLONG:
|
|
return false;
|
|
|
|
case VK_VE_HI32:
|
|
case VK_VE_LO32:
|
|
case VK_VE_PC_HI32:
|
|
case VK_VE_PC_LO32:
|
|
case VK_VE_GOT_HI32:
|
|
case VK_VE_GOT_LO32:
|
|
case VK_VE_GOTOFF_HI32:
|
|
case VK_VE_GOTOFF_LO32:
|
|
case VK_VE_PLT_HI32:
|
|
case VK_VE_PLT_LO32:
|
|
case VK_VE_TLS_GD_HI32:
|
|
case VK_VE_TLS_GD_LO32:
|
|
case VK_VE_TPOFF_HI32:
|
|
case VK_VE_TPOFF_LO32:
|
|
// Use suffix for these variant kinds
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void VEMCExpr::printVariantKindSuffix(raw_ostream &OS, VariantKind Kind) {
|
|
switch (Kind) {
|
|
case VK_VE_None:
|
|
case VK_VE_REFLONG:
|
|
break;
|
|
case VK_VE_HI32:
|
|
OS << "@hi";
|
|
break;
|
|
case VK_VE_LO32:
|
|
OS << "@lo";
|
|
break;
|
|
case VK_VE_PC_HI32:
|
|
OS << "@pc_hi";
|
|
break;
|
|
case VK_VE_PC_LO32:
|
|
OS << "@pc_lo";
|
|
break;
|
|
case VK_VE_GOT_HI32:
|
|
OS << "@got_hi";
|
|
break;
|
|
case VK_VE_GOT_LO32:
|
|
OS << "@got_lo";
|
|
break;
|
|
case VK_VE_GOTOFF_HI32:
|
|
OS << "@gotoff_hi";
|
|
break;
|
|
case VK_VE_GOTOFF_LO32:
|
|
OS << "@gotoff_lo";
|
|
break;
|
|
case VK_VE_PLT_HI32:
|
|
OS << "@plt_hi";
|
|
break;
|
|
case VK_VE_PLT_LO32:
|
|
OS << "@plt_lo";
|
|
break;
|
|
case VK_VE_TLS_GD_HI32:
|
|
OS << "@tls_gd_hi";
|
|
break;
|
|
case VK_VE_TLS_GD_LO32:
|
|
OS << "@tls_gd_lo";
|
|
break;
|
|
case VK_VE_TPOFF_HI32:
|
|
OS << "@tpoff_hi";
|
|
break;
|
|
case VK_VE_TPOFF_LO32:
|
|
OS << "@tpoff_lo";
|
|
break;
|
|
}
|
|
}
|
|
|
|
VEMCExpr::VariantKind VEMCExpr::parseVariantKind(StringRef name) {
|
|
return StringSwitch<VEMCExpr::VariantKind>(name)
|
|
.Case("hi", VK_VE_HI32)
|
|
.Case("lo", VK_VE_LO32)
|
|
.Case("pc_hi", VK_VE_PC_HI32)
|
|
.Case("pc_lo", VK_VE_PC_LO32)
|
|
.Case("got_hi", VK_VE_GOT_HI32)
|
|
.Case("got_lo", VK_VE_GOT_LO32)
|
|
.Case("gotoff_hi", VK_VE_GOTOFF_HI32)
|
|
.Case("gotoff_lo", VK_VE_GOTOFF_LO32)
|
|
.Case("plt_hi", VK_VE_PLT_HI32)
|
|
.Case("plt_lo", VK_VE_PLT_LO32)
|
|
.Case("tls_gd_hi", VK_VE_TLS_GD_HI32)
|
|
.Case("tls_gd_lo", VK_VE_TLS_GD_LO32)
|
|
.Case("tpoff_hi", VK_VE_TPOFF_HI32)
|
|
.Case("tpoff_lo", VK_VE_TPOFF_LO32)
|
|
.Default(VK_VE_None);
|
|
}
|
|
|
|
VE::Fixups VEMCExpr::getFixupKind(VEMCExpr::VariantKind Kind) {
|
|
switch (Kind) {
|
|
default:
|
|
llvm_unreachable("Unhandled VEMCExpr::VariantKind");
|
|
case VK_VE_REFLONG:
|
|
return VE::fixup_ve_reflong;
|
|
case VK_VE_HI32:
|
|
return VE::fixup_ve_hi32;
|
|
case VK_VE_LO32:
|
|
return VE::fixup_ve_lo32;
|
|
case VK_VE_PC_HI32:
|
|
return VE::fixup_ve_pc_hi32;
|
|
case VK_VE_PC_LO32:
|
|
return VE::fixup_ve_pc_lo32;
|
|
case VK_VE_GOT_HI32:
|
|
return VE::fixup_ve_got_hi32;
|
|
case VK_VE_GOT_LO32:
|
|
return VE::fixup_ve_got_lo32;
|
|
case VK_VE_GOTOFF_HI32:
|
|
return VE::fixup_ve_gotoff_hi32;
|
|
case VK_VE_GOTOFF_LO32:
|
|
return VE::fixup_ve_gotoff_lo32;
|
|
case VK_VE_PLT_HI32:
|
|
return VE::fixup_ve_plt_hi32;
|
|
case VK_VE_PLT_LO32:
|
|
return VE::fixup_ve_plt_lo32;
|
|
case VK_VE_TLS_GD_HI32:
|
|
return VE::fixup_ve_tls_gd_hi32;
|
|
case VK_VE_TLS_GD_LO32:
|
|
return VE::fixup_ve_tls_gd_lo32;
|
|
case VK_VE_TPOFF_HI32:
|
|
return VE::fixup_ve_tpoff_hi32;
|
|
case VK_VE_TPOFF_LO32:
|
|
return VE::fixup_ve_tpoff_lo32;
|
|
}
|
|
}
|
|
|
|
bool VEMCExpr::evaluateAsRelocatableImpl(MCValue &Res,
|
|
const MCAsmLayout *Layout,
|
|
const MCFixup *Fixup) const {
|
|
return getSubExpr()->evaluateAsRelocatable(Res, Layout, Fixup);
|
|
}
|
|
|
|
static void fixELFSymbolsInTLSFixupsImpl(const MCExpr *Expr, MCAssembler &Asm) {
|
|
switch (Expr->getKind()) {
|
|
case MCExpr::Target:
|
|
llvm_unreachable("Can't handle nested target expr!");
|
|
break;
|
|
|
|
case MCExpr::Constant:
|
|
break;
|
|
|
|
case MCExpr::Binary: {
|
|
const MCBinaryExpr *BE = cast<MCBinaryExpr>(Expr);
|
|
fixELFSymbolsInTLSFixupsImpl(BE->getLHS(), Asm);
|
|
fixELFSymbolsInTLSFixupsImpl(BE->getRHS(), Asm);
|
|
break;
|
|
}
|
|
|
|
case MCExpr::SymbolRef: {
|
|
// We're known to be under a TLS fixup, so any symbol should be
|
|
// modified. There should be only one.
|
|
const MCSymbolRefExpr &SymRef = *cast<MCSymbolRefExpr>(Expr);
|
|
cast<MCSymbolELF>(SymRef.getSymbol()).setType(ELF::STT_TLS);
|
|
break;
|
|
}
|
|
|
|
case MCExpr::Unary:
|
|
fixELFSymbolsInTLSFixupsImpl(cast<MCUnaryExpr>(Expr)->getSubExpr(), Asm);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void VEMCExpr::visitUsedExpr(MCStreamer &Streamer) const {
|
|
Streamer.visitUsedExpr(*getSubExpr());
|
|
}
|
|
|
|
void VEMCExpr::fixELFSymbolsInTLSFixups(MCAssembler &Asm) const {
|
|
switch (getKind()) {
|
|
default:
|
|
return;
|
|
case VK_VE_TLS_GD_HI32:
|
|
case VK_VE_TLS_GD_LO32:
|
|
case VK_VE_TPOFF_HI32:
|
|
case VK_VE_TPOFF_LO32:
|
|
break;
|
|
}
|
|
fixELFSymbolsInTLSFixupsImpl(getSubExpr(), Asm);
|
|
}
|