llvm-6502/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp
David Peixotto 0fc8c68b11 Add support for parsing ARM symbol variants on ELF targets
ARM symbol variants are written with parens instead of @ like this:

  .word __GLOBAL_I_a(target1)

This commit adds support for parsing these symbol variants in
expressions. We introduce a new flag to MCAsmInfo that indicates the
parser should use parens to parse the symbol variant. The expression
parser is modified to look for symbol variants using parens instead
of @ when the corresponding MCAsmInfo flag is true.

The MCAsmInfo parens flag is enabled only for ARM on ELF.

By adding this flag to MCAsmInfo, we are able to get rid of
redundant ARM-specific symbol variants and use the generic variants
instead (e.g. VK_GOT instead of VK_ARM_GOT). We use the new
UseParensForSymbolVariant attribute in MCAsmInfo to correctly print
the symbol variants for arm.

To achive this we need to keep a handle to the MCAsmInfo in the
MCSymbolRefExpr class that we can check when printing the symbol
variant.

Updated Tests:
  Changed case of symbol variant to match the generic kind.
  test/CodeGen/ARM/tls-models.ll
  test/CodeGen/ARM/tls1.ll
  test/CodeGen/ARM/tls2.ll
  test/CodeGen/Thumb2/tls1.ll
  test/CodeGen/Thumb2/tls2.ll

PR18080


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@196424 91177308-0d34-0410-b5e6-96231b3b80d8
2013-12-04 22:43:20 +00:00

290 lines
9.4 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();
virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup,
bool IsPCRel, bool IsRelocWithSymbol,
int64_t Addend) const;
virtual const MCSymbol *ExplicitRelSym(const MCAssembler &Asm,
const MCValue &Target,
const MCFragment &F,
const MCFixup &Fixup,
bool IsPCRel) const;
};
}
ARMELFObjectWriter::ARMELFObjectWriter(uint8_t OSABI)
: MCELFObjectTargetWriter(/*Is64Bit*/ false, OSABI,
ELF::EM_ARM,
/*HasRelocationAddend*/ false) {}
ARMELFObjectWriter::~ARMELFObjectWriter() {}
// In ARM, _MergedGlobals and other most symbols get emitted directly.
// I.e. not as an offset to a section symbol.
// This code is an approximation of what ARM/gcc does.
STATISTIC(PCRelCount, "Total number of PIC Relocations");
STATISTIC(NonPCRelCount, "Total number of non-PIC relocations");
const MCSymbol *ARMELFObjectWriter::ExplicitRelSym(const MCAssembler &Asm,
const MCValue &Target,
const MCFragment &F,
const MCFixup &Fixup,
bool IsPCRel) const {
const MCSymbol &Symbol = Target.getSymA()->getSymbol().AliasedSymbol();
bool EmitThisSym = false;
const MCSectionELF &Section =
static_cast<const MCSectionELF&>(Symbol.getSection());
bool InNormalSection = true;
unsigned RelocType = 0;
RelocType = GetRelocTypeInner(Target, Fixup, IsPCRel);
DEBUG(
const MCSymbolRefExpr::VariantKind Kind = Target.getSymA()->getKind();
MCSymbolRefExpr::VariantKind Kind2;
Kind2 = Target.getSymB() ? Target.getSymB()->getKind() :
MCSymbolRefExpr::VK_None;
dbgs() << "considering symbol "
<< Section.getSectionName() << "/"
<< Symbol.getName() << "/"
<< " Rel:" << (unsigned)RelocType
<< " Kind: " << (int)Kind << "/" << (int)Kind2
<< " Tmp:"
<< Symbol.isAbsolute() << "/" << Symbol.isDefined() << "/"
<< Symbol.isVariable() << "/" << Symbol.isTemporary()
<< " Counts:" << PCRelCount << "/" << NonPCRelCount << "\n");
if (IsPCRel) { ++PCRelCount;
switch (RelocType) {
default:
// Most relocation types are emitted as explicit symbols
InNormalSection =
StringSwitch<bool>(Section.getSectionName())
.Case(".data.rel.ro.local", false)
.Case(".data.rel", false)
.Case(".bss", false)
.Default(true);
EmitThisSym = true;
break;
case ELF::R_ARM_ABS32:
// But things get strange with R_ARM_ABS32
// In this case, most things that go in .rodata show up
// as section relative relocations
InNormalSection =
StringSwitch<bool>(Section.getSectionName())
.Case(".data.rel.ro.local", false)
.Case(".data.rel", false)
.Case(".rodata", false)
.Case(".bss", false)
.Default(true);
EmitThisSym = false;
break;
}
} else {
NonPCRelCount++;
InNormalSection =
StringSwitch<bool>(Section.getSectionName())
.Case(".data.rel.ro.local", false)
.Case(".rodata", false)
.Case(".data.rel", false)
.Case(".bss", false)
.Default(true);
switch (RelocType) {
default: EmitThisSym = true; break;
case ELF::R_ARM_ABS32: EmitThisSym = false; break;
case ELF::R_ARM_PREL31: EmitThisSym = false; break;
}
}
if (EmitThisSym)
return &Symbol;
if (! Symbol.isTemporary() && InNormalSection) {
return &Symbol;
}
return NULL;
}
// 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,
bool IsRelocWithSymbol,
int64_t Addend) const {
return GetRelocTypeInner(Target, Fixup, IsPCRel);
}
unsigned ARMELFObjectWriter::GetRelocTypeInner(const MCValue &Target,
const MCFixup &Fixup,
bool IsPCRel) const {
MCSymbolRefExpr::VariantKind Modifier = Target.isAbsolute() ?
MCSymbolRefExpr::VK_None : Target.getSymA()->getKind();
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;
}
break;
case ARM::fixup_arm_blx:
case ARM::fixup_arm_uncondbl:
switch (Modifier) {
case MCSymbolRefExpr::VK_PLT:
Type = ELF::R_ARM_PLT32;
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:
case ARM::fixup_arm_movt_hi16_pcrel:
Type = ELF::R_ARM_MOVT_PREL;
break;
case ARM::fixup_arm_movw_lo16:
case ARM::fixup_arm_movw_lo16_pcrel:
Type = ELF::R_ARM_MOVW_PREL_NC;
break;
case ARM::fixup_t2_movt_hi16:
case ARM::fixup_t2_movt_hi16_pcrel:
Type = ELF::R_ARM_THM_MOVT_PREL;
break;
case ARM::fixup_t2_movw_lo16:
case ARM::fixup_t2_movw_lo16_pcrel:
Type = ELF::R_ARM_THM_MOVW_PREL_NC;
break;
case ARM::fixup_arm_thumb_bl:
case ARM::fixup_arm_thumb_blx:
Type = ELF::R_ARM_THM_CALL;
break;
}
} else {
switch ((unsigned)Fixup.getKind()) {
default: llvm_unreachable("invalid fixup kind!");
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_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;
}
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) {
MCELFObjectTargetWriter *MOTW = new ARMELFObjectWriter(OSABI);
return createELFObjectWriter(MOTW, OS, /*IsLittleEndian=*/true);
}