mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-02-06 06:33:24 +00:00
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
290 lines
9.4 KiB
C++
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);
|
|
}
|