llvm-6502/lib/Target/SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp
Ulrich Weigand 1d09d56fe1 [SystemZ] Add back end
This adds the actual lib/Target/SystemZ target files necessary to
implement the SystemZ target.  Note that at this point, the target
cannot yet be built since the configure bits are missing.  Those
will be provided shortly by a follow-on patch.

This version of the patch incorporates feedback from reviews by
Chris Lattner and Anton Korobeynikov.  Thanks to all reviewers!

Patch by Richard Sandiford.



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@181203 91177308-0d34-0410-b5e6-96231b3b80d8
2013-05-06 16:15:19 +00:00

141 lines
5.3 KiB
C++

//===-- SystemZMCObjectWriter.cpp - SystemZ ELF writer --------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "MCTargetDesc/SystemZMCTargetDesc.h"
#include "MCTargetDesc/SystemZMCFixups.h"
#include "llvm/MC/MCELFObjectWriter.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCValue.h"
using namespace llvm;
namespace {
class SystemZObjectWriter : public MCELFObjectTargetWriter {
public:
SystemZObjectWriter(uint8_t OSABI);
virtual ~SystemZObjectWriter();
protected:
// Override MCELFObjectTargetWriter.
virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup,
bool IsPCRel, bool IsRelocWithSymbol,
int64_t Addend) const LLVM_OVERRIDE;
virtual const MCSymbol *ExplicitRelSym(const MCAssembler &Asm,
const MCValue &Target,
const MCFragment &F,
const MCFixup &Fixup,
bool IsPCRel) const LLVM_OVERRIDE;
};
} // end anonymouse namespace
SystemZObjectWriter::SystemZObjectWriter(uint8_t OSABI)
: MCELFObjectTargetWriter(/*Is64Bit=*/true, OSABI, ELF::EM_S390,
/*HasRelocationAddend=*/ true) {}
SystemZObjectWriter::~SystemZObjectWriter() {
}
// Return the relocation type for an absolute value of MCFixupKind Kind.
static unsigned getAbsoluteReloc(unsigned Kind) {
switch (Kind) {
case FK_Data_1: return ELF::R_390_8;
case FK_Data_2: return ELF::R_390_16;
case FK_Data_4: return ELF::R_390_32;
case FK_Data_8: return ELF::R_390_64;
}
llvm_unreachable("Unsupported absolute address");
}
// Return the relocation type for a PC-relative value of MCFixupKind Kind.
static unsigned getPCRelReloc(unsigned Kind) {
switch (Kind) {
case FK_Data_2: return ELF::R_390_PC16;
case FK_Data_4: return ELF::R_390_PC32;
case FK_Data_8: return ELF::R_390_PC64;
case SystemZ::FK_390_PC16DBL: return ELF::R_390_PC16DBL;
case SystemZ::FK_390_PC32DBL: return ELF::R_390_PC32DBL;
case SystemZ::FK_390_PLT16DBL: return ELF::R_390_PLT16DBL;
case SystemZ::FK_390_PLT32DBL: return ELF::R_390_PLT32DBL;
}
llvm_unreachable("Unsupported PC-relative address");
}
// Return the R_390_TLS_LE* relocation type for MCFixupKind Kind.
static unsigned getTLSLEReloc(unsigned Kind) {
switch (Kind) {
case FK_Data_4: return ELF::R_390_TLS_LE32;
case FK_Data_8: return ELF::R_390_TLS_LE64;
}
llvm_unreachable("Unsupported absolute address");
}
// Return the PLT relocation counterpart of MCFixupKind Kind.
static unsigned getPLTReloc(unsigned Kind) {
switch (Kind) {
case SystemZ::FK_390_PC16DBL: return ELF::R_390_PLT16DBL;
case SystemZ::FK_390_PC32DBL: return ELF::R_390_PLT32DBL;
}
llvm_unreachable("Unsupported absolute address");
}
unsigned SystemZObjectWriter::GetRelocType(const MCValue &Target,
const MCFixup &Fixup,
bool IsPCRel,
bool IsRelocWithSymbol,
int64_t Addend) const {
MCSymbolRefExpr::VariantKind Modifier = (Target.isAbsolute() ?
MCSymbolRefExpr::VK_None :
Target.getSymA()->getKind());
unsigned Kind = Fixup.getKind();
switch (Modifier) {
case MCSymbolRefExpr::VK_None:
if (IsPCRel)
return getPCRelReloc(Kind);
return getAbsoluteReloc(Kind);
case MCSymbolRefExpr::VK_NTPOFF:
assert(!IsPCRel && "NTPOFF shouldn't be PC-relative");
return getTLSLEReloc(Kind);
case MCSymbolRefExpr::VK_GOT:
if (IsPCRel && Kind == SystemZ::FK_390_PC32DBL)
return ELF::R_390_GOTENT;
llvm_unreachable("Only PC-relative GOT accesses are supported for now");
case MCSymbolRefExpr::VK_PLT:
assert(IsPCRel && "@PLT shouldt be PC-relative");
return getPLTReloc(Kind);
default:
llvm_unreachable("Modifier not supported");
}
}
const MCSymbol *SystemZObjectWriter::ExplicitRelSym(const MCAssembler &Asm,
const MCValue &Target,
const MCFragment &F,
const MCFixup &Fixup,
bool IsPCRel) const {
// The addend in a PC-relative R_390_* relocation is always applied to
// the PC-relative part of the address. If some kind of indirection
// is applied to the symbol first, we can't use an addend there too.
if (!Target.isAbsolute() &&
Target.getSymA()->getKind() != MCSymbolRefExpr::VK_None &&
IsPCRel)
return &Target.getSymA()->getSymbol().AliasedSymbol();
return NULL;
}
MCObjectWriter *llvm::createSystemZObjectWriter(raw_ostream &OS,
uint8_t OSABI) {
MCELFObjectTargetWriter *MOTW = new SystemZObjectWriter(OSABI);
return createELFObjectWriter(MOTW, OS, /*IsLittleEndian=*/false);
}