mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-01 08:23:21 +01:00
7cd7b1f749
and update ELF header e_flags. Currently gathering information such as symbol, section and data is done by collecting it in an MCAssembler object. From MCAssembler and MCAsmLayout objects ELFObjectWriter::WriteObject() forms and streams out the ELF object file. This patch just adds a few members to the MCAssember class to store and access the e_flag settings. It allows for runtime additions to the e_flag by assembler directives. The standalone assembler can get to MCAssembler from getParser().getStreamer().getAssembler(). This patch is the generic infrastructure and will be followed by patches for ARM and Mips for their target specific use. Contributer: Jack Carter llvm-svn: 173882
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_ARM_TLSGD:
|
|
llvm_unreachable("unimplemented");
|
|
case MCSymbolRefExpr::VK_ARM_GOTTPOFF:
|
|
Type = ELF::R_ARM_TLS_IE32;
|
|
break;
|
|
}
|
|
break;
|
|
case ARM::fixup_arm_blx:
|
|
case ARM::fixup_arm_uncondbl:
|
|
switch (Modifier) {
|
|
case MCSymbolRefExpr::VK_ARM_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_ARM_GOT:
|
|
Type = ELF::R_ARM_GOT_BREL;
|
|
break;
|
|
case MCSymbolRefExpr::VK_ARM_TLSGD:
|
|
Type = ELF::R_ARM_TLS_GD32;
|
|
break;
|
|
case MCSymbolRefExpr::VK_ARM_TPOFF:
|
|
Type = ELF::R_ARM_TLS_LE32;
|
|
break;
|
|
case MCSymbolRefExpr::VK_ARM_GOTTPOFF:
|
|
Type = ELF::R_ARM_TLS_IE32;
|
|
break;
|
|
case MCSymbolRefExpr::VK_None:
|
|
Type = ELF::R_ARM_ABS32;
|
|
break;
|
|
case MCSymbolRefExpr::VK_ARM_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);
|
|
}
|