llvm-6502/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp
Saleem Abdulrasool 5e3c87ee1a ARM: add support for segment base relocations (SBREL)
This adds support for parsing and emitting the SBREL relocation variant for the
ARM target.  Handling this relocation variant is necessary for supporting the
full ARM ELF specification.  Addresses PR22128.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@225595 91177308-0d34-0410-b5e6-96231b3b80d8
2015-01-11 04:39:18 +00:00

256 lines
7.6 KiB
C++

//===-- ARMELFObjectWriter.cpp - ARM 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/ARMMCTargetDesc.h"
#include "MCTargetDesc/ARMFixupKinds.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/MC/MCELFObjectWriter.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCSectionELF.h"
#include "llvm/MC/MCValue.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
namespace {
class ARMELFObjectWriter : public MCELFObjectTargetWriter {
enum { DefaultEABIVersion = 0x05000000U };
unsigned GetRelocTypeInner(const MCValue &Target,
const MCFixup &Fixup,
bool IsPCRel) const;
public:
ARMELFObjectWriter(uint8_t OSABI);
virtual ~ARMELFObjectWriter();
unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup,
bool IsPCRel) const override;
bool needsRelocateWithSymbol(const MCSymbolData &SD,
unsigned Type) const override;
};
}
ARMELFObjectWriter::ARMELFObjectWriter(uint8_t OSABI)
: MCELFObjectTargetWriter(/*Is64Bit*/ false, OSABI,
ELF::EM_ARM,
/*HasRelocationAddend*/ false) {}
ARMELFObjectWriter::~ARMELFObjectWriter() {}
bool ARMELFObjectWriter::needsRelocateWithSymbol(const MCSymbolData &SD,
unsigned Type) const {
// FIXME: This is extremely conservative. This really needs to use a
// whitelist with a clear explanation for why each realocation needs to
// point to the symbol, not to the section.
switch (Type) {
default:
return true;
case ELF::R_ARM_PREL31:
case ELF::R_ARM_ABS32:
return false;
}
}
// Need to examine the Fixup when determining whether to
// emit the relocation as an explicit symbol or as a section relative
// offset
unsigned ARMELFObjectWriter::GetRelocType(const MCValue &Target,
const MCFixup &Fixup,
bool IsPCRel) const {
return GetRelocTypeInner(Target, Fixup, IsPCRel);
}
unsigned ARMELFObjectWriter::GetRelocTypeInner(const MCValue &Target,
const MCFixup &Fixup,
bool IsPCRel) const {
MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant();
unsigned Type = 0;
if (IsPCRel) {
switch ((unsigned)Fixup.getKind()) {
default: llvm_unreachable("Unimplemented");
case FK_Data_4:
switch (Modifier) {
default: llvm_unreachable("Unsupported Modifier");
case MCSymbolRefExpr::VK_None:
Type = ELF::R_ARM_REL32;
break;
case MCSymbolRefExpr::VK_TLSGD:
llvm_unreachable("unimplemented");
case MCSymbolRefExpr::VK_GOTTPOFF:
Type = ELF::R_ARM_TLS_IE32;
break;
case MCSymbolRefExpr::VK_GOTPCREL:
Type = ELF::R_ARM_GOT_PREL;
break;
}
break;
case ARM::fixup_arm_blx:
case ARM::fixup_arm_uncondbl:
switch (Modifier) {
case MCSymbolRefExpr::VK_PLT:
Type = ELF::R_ARM_CALL;
break;
case MCSymbolRefExpr::VK_ARM_TLSCALL:
Type = ELF::R_ARM_TLS_CALL;
break;
default:
Type = ELF::R_ARM_CALL;
break;
}
break;
case ARM::fixup_arm_condbl:
case ARM::fixup_arm_condbranch:
case ARM::fixup_arm_uncondbranch:
Type = ELF::R_ARM_JUMP24;
break;
case ARM::fixup_t2_condbranch:
case ARM::fixup_t2_uncondbranch:
Type = ELF::R_ARM_THM_JUMP24;
break;
case ARM::fixup_arm_movt_hi16:
Type = ELF::R_ARM_MOVT_PREL;
break;
case ARM::fixup_arm_movw_lo16:
Type = ELF::R_ARM_MOVW_PREL_NC;
break;
case ARM::fixup_t2_movt_hi16:
Type = ELF::R_ARM_THM_MOVT_PREL;
break;
case ARM::fixup_t2_movw_lo16:
Type = ELF::R_ARM_THM_MOVW_PREL_NC;
break;
case ARM::fixup_arm_thumb_bl:
case ARM::fixup_arm_thumb_blx:
switch (Modifier) {
case MCSymbolRefExpr::VK_ARM_TLSCALL:
Type = ELF::R_ARM_THM_TLS_CALL;
break;
default:
Type = ELF::R_ARM_THM_CALL;
break;
}
break;
}
} else {
switch ((unsigned)Fixup.getKind()) {
default: llvm_unreachable("invalid fixup kind!");
case FK_Data_1:
switch (Modifier) {
default: llvm_unreachable("unsupported Modifier");
case MCSymbolRefExpr::VK_None:
Type = ELF::R_ARM_ABS8;
break;
}
break;
case FK_Data_2:
switch (Modifier) {
default: llvm_unreachable("unsupported modifier");
case MCSymbolRefExpr::VK_None:
Type = ELF::R_ARM_ABS16;
break;
}
break;
case FK_Data_4:
switch (Modifier) {
default: llvm_unreachable("Unsupported Modifier");
case MCSymbolRefExpr::VK_ARM_NONE:
Type = ELF::R_ARM_NONE;
break;
case MCSymbolRefExpr::VK_GOT:
Type = ELF::R_ARM_GOT_BREL;
break;
case MCSymbolRefExpr::VK_TLSGD:
Type = ELF::R_ARM_TLS_GD32;
break;
case MCSymbolRefExpr::VK_TPOFF:
Type = ELF::R_ARM_TLS_LE32;
break;
case MCSymbolRefExpr::VK_GOTTPOFF:
Type = ELF::R_ARM_TLS_IE32;
break;
case MCSymbolRefExpr::VK_None:
Type = ELF::R_ARM_ABS32;
break;
case MCSymbolRefExpr::VK_GOTOFF:
Type = ELF::R_ARM_GOTOFF32;
break;
case MCSymbolRefExpr::VK_GOTPCREL:
Type = ELF::R_ARM_GOT_PREL;
break;
case MCSymbolRefExpr::VK_ARM_TARGET1:
Type = ELF::R_ARM_TARGET1;
break;
case MCSymbolRefExpr::VK_ARM_TARGET2:
Type = ELF::R_ARM_TARGET2;
break;
case MCSymbolRefExpr::VK_ARM_PREL31:
Type = ELF::R_ARM_PREL31;
break;
case MCSymbolRefExpr::VK_ARM_SBREL:
Type = ELF::R_ARM_SBREL32;
break;
case MCSymbolRefExpr::VK_ARM_TLSLDO:
Type = ELF::R_ARM_TLS_LDO32;
break;
case MCSymbolRefExpr::VK_ARM_TLSCALL:
Type = ELF::R_ARM_TLS_CALL;
break;
case MCSymbolRefExpr::VK_ARM_TLSDESC:
Type = ELF::R_ARM_TLS_GOTDESC;
break;
case MCSymbolRefExpr::VK_ARM_TLSDESCSEQ:
Type = ELF::R_ARM_TLS_DESCSEQ;
break;
}
break;
case ARM::fixup_arm_ldst_pcrel_12:
case ARM::fixup_arm_pcrel_10:
case ARM::fixup_arm_adr_pcrel_12:
case ARM::fixup_arm_thumb_bl:
case ARM::fixup_arm_thumb_cb:
case ARM::fixup_arm_thumb_cp:
case ARM::fixup_arm_thumb_br:
llvm_unreachable("Unimplemented");
case ARM::fixup_arm_condbranch:
case ARM::fixup_arm_uncondbranch:
Type = ELF::R_ARM_JUMP24;
break;
case ARM::fixup_arm_movt_hi16:
Type = ELF::R_ARM_MOVT_ABS;
break;
case ARM::fixup_arm_movw_lo16:
Type = ELF::R_ARM_MOVW_ABS_NC;
break;
case ARM::fixup_t2_movt_hi16:
Type = ELF::R_ARM_THM_MOVT_ABS;
break;
case ARM::fixup_t2_movw_lo16:
Type = ELF::R_ARM_THM_MOVW_ABS_NC;
break;
}
}
return Type;
}
MCObjectWriter *llvm::createARMELFObjectWriter(raw_ostream &OS,
uint8_t OSABI,
bool IsLittleEndian) {
MCELFObjectTargetWriter *MOTW = new ARMELFObjectWriter(OSABI);
return createELFObjectWriter(MOTW, OS, IsLittleEndian);
}