forked from OSchip/llvm-project
274 lines
8.1 KiB
C++
274 lines
8.1 KiB
C++
//===-- MipsELFObjectWriter.cpp - Mips 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/MipsBaseInfo.h"
|
|
#include "MCTargetDesc/MipsFixupKinds.h"
|
|
#include "MCTargetDesc/MipsMCTargetDesc.h"
|
|
#include "llvm/MC/MCAssembler.h"
|
|
#include "llvm/MC/MCELF.h"
|
|
#include "llvm/MC/MCELFObjectWriter.h"
|
|
#include "llvm/MC/MCExpr.h"
|
|
#include "llvm/MC/MCSection.h"
|
|
#include "llvm/MC/MCValue.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
#include <list>
|
|
|
|
using namespace llvm;
|
|
|
|
namespace {
|
|
class MipsELFObjectWriter : public MCELFObjectTargetWriter {
|
|
public:
|
|
MipsELFObjectWriter(bool _is64Bit, uint8_t OSABI,
|
|
bool _isN64, bool IsLittleEndian);
|
|
|
|
virtual ~MipsELFObjectWriter();
|
|
|
|
unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup,
|
|
bool IsPCRel) const override;
|
|
bool needsRelocateWithSymbol(const MCSymbolData &SD,
|
|
unsigned Type) const override;
|
|
};
|
|
}
|
|
|
|
MipsELFObjectWriter::MipsELFObjectWriter(bool _is64Bit, uint8_t OSABI,
|
|
bool _isN64, bool IsLittleEndian)
|
|
: MCELFObjectTargetWriter(_is64Bit, OSABI, ELF::EM_MIPS,
|
|
/*HasRelocationAddend*/ _isN64,
|
|
/*IsN64*/ _isN64) {}
|
|
|
|
MipsELFObjectWriter::~MipsELFObjectWriter() {}
|
|
|
|
unsigned MipsELFObjectWriter::GetRelocType(const MCValue &Target,
|
|
const MCFixup &Fixup,
|
|
bool IsPCRel) const {
|
|
// determine the type of the relocation
|
|
unsigned Type = (unsigned)ELF::R_MIPS_NONE;
|
|
unsigned Kind = (unsigned)Fixup.getKind();
|
|
|
|
switch (Kind) {
|
|
default:
|
|
llvm_unreachable("invalid fixup kind!");
|
|
case Mips::fixup_Mips_32:
|
|
case FK_Data_4:
|
|
Type = ELF::R_MIPS_32;
|
|
break;
|
|
case Mips::fixup_Mips_64:
|
|
case FK_Data_8:
|
|
Type = ELF::R_MIPS_64;
|
|
break;
|
|
case FK_GPRel_4:
|
|
if (isN64()) {
|
|
Type = setRType((unsigned)ELF::R_MIPS_GPREL32, Type);
|
|
Type = setRType2((unsigned)ELF::R_MIPS_64, Type);
|
|
Type = setRType3((unsigned)ELF::R_MIPS_NONE, Type);
|
|
}
|
|
else
|
|
Type = ELF::R_MIPS_GPREL32;
|
|
break;
|
|
case Mips::fixup_Mips_GPREL16:
|
|
Type = ELF::R_MIPS_GPREL16;
|
|
break;
|
|
case Mips::fixup_Mips_26:
|
|
Type = ELF::R_MIPS_26;
|
|
break;
|
|
case Mips::fixup_Mips_CALL16:
|
|
Type = ELF::R_MIPS_CALL16;
|
|
break;
|
|
case Mips::fixup_Mips_GOT_Global:
|
|
case Mips::fixup_Mips_GOT_Local:
|
|
Type = ELF::R_MIPS_GOT16;
|
|
break;
|
|
case Mips::fixup_Mips_HI16:
|
|
Type = ELF::R_MIPS_HI16;
|
|
break;
|
|
case Mips::fixup_Mips_LO16:
|
|
Type = ELF::R_MIPS_LO16;
|
|
break;
|
|
case Mips::fixup_Mips_TLSGD:
|
|
Type = ELF::R_MIPS_TLS_GD;
|
|
break;
|
|
case Mips::fixup_Mips_GOTTPREL:
|
|
Type = ELF::R_MIPS_TLS_GOTTPREL;
|
|
break;
|
|
case Mips::fixup_Mips_TPREL_HI:
|
|
Type = ELF::R_MIPS_TLS_TPREL_HI16;
|
|
break;
|
|
case Mips::fixup_Mips_TPREL_LO:
|
|
Type = ELF::R_MIPS_TLS_TPREL_LO16;
|
|
break;
|
|
case Mips::fixup_Mips_TLSLDM:
|
|
Type = ELF::R_MIPS_TLS_LDM;
|
|
break;
|
|
case Mips::fixup_Mips_DTPREL_HI:
|
|
Type = ELF::R_MIPS_TLS_DTPREL_HI16;
|
|
break;
|
|
case Mips::fixup_Mips_DTPREL_LO:
|
|
Type = ELF::R_MIPS_TLS_DTPREL_LO16;
|
|
break;
|
|
case Mips::fixup_Mips_Branch_PCRel:
|
|
case Mips::fixup_Mips_PC16:
|
|
Type = ELF::R_MIPS_PC16;
|
|
break;
|
|
case Mips::fixup_Mips_GOT_PAGE:
|
|
Type = ELF::R_MIPS_GOT_PAGE;
|
|
break;
|
|
case Mips::fixup_Mips_GOT_OFST:
|
|
Type = ELF::R_MIPS_GOT_OFST;
|
|
break;
|
|
case Mips::fixup_Mips_GOT_DISP:
|
|
Type = ELF::R_MIPS_GOT_DISP;
|
|
break;
|
|
case Mips::fixup_Mips_GPOFF_HI:
|
|
Type = setRType((unsigned)ELF::R_MIPS_GPREL16, Type);
|
|
Type = setRType2((unsigned)ELF::R_MIPS_SUB, Type);
|
|
Type = setRType3((unsigned)ELF::R_MIPS_HI16, Type);
|
|
break;
|
|
case Mips::fixup_Mips_GPOFF_LO:
|
|
Type = setRType((unsigned)ELF::R_MIPS_GPREL16, Type);
|
|
Type = setRType2((unsigned)ELF::R_MIPS_SUB, Type);
|
|
Type = setRType3((unsigned)ELF::R_MIPS_LO16, Type);
|
|
break;
|
|
case Mips::fixup_Mips_HIGHER:
|
|
Type = ELF::R_MIPS_HIGHER;
|
|
break;
|
|
case Mips::fixup_Mips_HIGHEST:
|
|
Type = ELF::R_MIPS_HIGHEST;
|
|
break;
|
|
case Mips::fixup_Mips_GOT_HI16:
|
|
Type = ELF::R_MIPS_GOT_HI16;
|
|
break;
|
|
case Mips::fixup_Mips_GOT_LO16:
|
|
Type = ELF::R_MIPS_GOT_LO16;
|
|
break;
|
|
case Mips::fixup_Mips_CALL_HI16:
|
|
Type = ELF::R_MIPS_CALL_HI16;
|
|
break;
|
|
case Mips::fixup_Mips_CALL_LO16:
|
|
Type = ELF::R_MIPS_CALL_LO16;
|
|
break;
|
|
case Mips::fixup_MICROMIPS_26_S1:
|
|
Type = ELF::R_MICROMIPS_26_S1;
|
|
break;
|
|
case Mips::fixup_MICROMIPS_HI16:
|
|
Type = ELF::R_MICROMIPS_HI16;
|
|
break;
|
|
case Mips::fixup_MICROMIPS_LO16:
|
|
Type = ELF::R_MICROMIPS_LO16;
|
|
break;
|
|
case Mips::fixup_MICROMIPS_GOT16:
|
|
Type = ELF::R_MICROMIPS_GOT16;
|
|
break;
|
|
case Mips::fixup_MICROMIPS_PC7_S1:
|
|
Type = ELF::R_MICROMIPS_PC7_S1;
|
|
break;
|
|
case Mips::fixup_MICROMIPS_PC10_S1:
|
|
Type = ELF::R_MICROMIPS_PC10_S1;
|
|
break;
|
|
case Mips::fixup_MICROMIPS_PC16_S1:
|
|
Type = ELF::R_MICROMIPS_PC16_S1;
|
|
break;
|
|
case Mips::fixup_MICROMIPS_CALL16:
|
|
Type = ELF::R_MICROMIPS_CALL16;
|
|
break;
|
|
case Mips::fixup_MICROMIPS_GOT_DISP:
|
|
Type = ELF::R_MICROMIPS_GOT_DISP;
|
|
break;
|
|
case Mips::fixup_MICROMIPS_GOT_PAGE:
|
|
Type = ELF::R_MICROMIPS_GOT_PAGE;
|
|
break;
|
|
case Mips::fixup_MICROMIPS_GOT_OFST:
|
|
Type = ELF::R_MICROMIPS_GOT_OFST;
|
|
break;
|
|
case Mips::fixup_MICROMIPS_TLS_GD:
|
|
Type = ELF::R_MICROMIPS_TLS_GD;
|
|
break;
|
|
case Mips::fixup_MICROMIPS_TLS_LDM:
|
|
Type = ELF::R_MICROMIPS_TLS_LDM;
|
|
break;
|
|
case Mips::fixup_MICROMIPS_TLS_DTPREL_HI16:
|
|
Type = ELF::R_MICROMIPS_TLS_DTPREL_HI16;
|
|
break;
|
|
case Mips::fixup_MICROMIPS_TLS_DTPREL_LO16:
|
|
Type = ELF::R_MICROMIPS_TLS_DTPREL_LO16;
|
|
break;
|
|
case Mips::fixup_MICROMIPS_TLS_TPREL_HI16:
|
|
Type = ELF::R_MICROMIPS_TLS_TPREL_HI16;
|
|
break;
|
|
case Mips::fixup_MICROMIPS_TLS_TPREL_LO16:
|
|
Type = ELF::R_MICROMIPS_TLS_TPREL_LO16;
|
|
break;
|
|
case Mips::fixup_MIPS_PC19_S2:
|
|
Type = ELF::R_MIPS_PC19_S2;
|
|
break;
|
|
case Mips::fixup_MIPS_PC18_S3:
|
|
Type = ELF::R_MIPS_PC18_S3;
|
|
break;
|
|
case Mips::fixup_MIPS_PC21_S2:
|
|
Type = ELF::R_MIPS_PC21_S2;
|
|
break;
|
|
case Mips::fixup_MIPS_PC26_S2:
|
|
Type = ELF::R_MIPS_PC26_S2;
|
|
break;
|
|
case Mips::fixup_MIPS_PCHI16:
|
|
Type = ELF::R_MIPS_PCHI16;
|
|
break;
|
|
case Mips::fixup_MIPS_PCLO16:
|
|
Type = ELF::R_MIPS_PCLO16;
|
|
break;
|
|
}
|
|
return Type;
|
|
}
|
|
|
|
bool
|
|
MipsELFObjectWriter::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_MIPS_GOT16:
|
|
case ELF::R_MIPS16_GOT16:
|
|
case ELF::R_MICROMIPS_GOT16:
|
|
llvm_unreachable("Should have been handled already");
|
|
|
|
// These relocations might be paired with another relocation. The pairing is
|
|
// done by the static linker by matching the symbol. Since we only see one
|
|
// relocation at a time, we have to force them to relocate with a symbol to
|
|
// avoid ending up with a pair where one points to a section and another
|
|
// points to a symbol.
|
|
case ELF::R_MIPS_HI16:
|
|
case ELF::R_MIPS16_HI16:
|
|
case ELF::R_MICROMIPS_HI16:
|
|
case ELF::R_MIPS_LO16:
|
|
case ELF::R_MIPS16_LO16:
|
|
case ELF::R_MICROMIPS_LO16:
|
|
return true;
|
|
|
|
case ELF::R_MIPS_32:
|
|
if (MCELF::getOther(SD) & (ELF::STO_MIPS_MICROMIPS >> 2))
|
|
return true;
|
|
// falltrough
|
|
case ELF::R_MIPS_26:
|
|
case ELF::R_MIPS_64:
|
|
case ELF::R_MIPS_GPREL16:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
MCObjectWriter *llvm::createMipsELFObjectWriter(raw_ostream &OS, uint8_t OSABI,
|
|
bool IsLittleEndian,
|
|
bool Is64Bit) {
|
|
MCELFObjectTargetWriter *MOTW =
|
|
new MipsELFObjectWriter(Is64Bit, OSABI, Is64Bit, IsLittleEndian);
|
|
return createELFObjectWriter(MOTW, OS, IsLittleEndian);
|
|
}
|