1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-21 20:12:56 +02:00
llvm-mirror/include/llvm/MC/MCELFObjectWriter.h
Daniel Sanders cd4dc5cad8 [mips] Correct the ordering of HI/LO pairs in the relocation table.
Summary:
There seems to have been a misunderstanding as to the meaning of 'offset' in
the rules laid down by our ABI. The previous code believed that 'offset' meant
the offset within the section that the relocation is applied to. However, it
should have meant the offset from the symbol used in the relocation expression.

This patch adds two fields to ELFRelocationEntry and uses them to correct the
order of relocations for MIPS. These fields contain:
* The original symbol before shouldRelocateWithSymbol() is considered. This
  ensures that R_MIPS_GOT16 is able to correctly distinguish between local and
  external symbols, allowing us to tell whether %got() requires a matching
  %lo() or not (local symbols require one, external symbols don't). It also
  prevents confusing cases where the fuzzy matching rules cause things like
  %hi(foo)/%lo(foo+3) and %hi(bar)/%lo(bar+1) to swap their %lo()'s.
* The original offset before shouldRelocateWithSymbol() is considered. The
  existing Addend field is always zero when the object uses in place addends
  (because it's already moved it to the encoding) but MIPS needs to use the
  original offset to ensure that the linker correctly calculates the carry-in
  bit for %hi() and %got().

IAS ensures that unmatchable %hi()/%got() relocations are placed at the end of
the table to ensure that the linker rejects the table (we're unable to report
such errors directly). The alternatives to this risk accidental matching
against inappropriate relocations which may silently compute incorrect values
due to an incorrect carry bit between the %lo() and %hi()/%got().

Reviewers: sdardis

Subscribers: dsanders, sdardis, rafael, llvm-commits

Differential Revision: http://reviews.llvm.org/D19718

llvm-svn: 268733
2016-05-06 13:49:25 +00:00

149 lines
4.8 KiB
C++

//===-- llvm/MC/MCELFObjectWriter.h - ELF Object Writer ---------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_MC_MCELFOBJECTWRITER_H
#define LLVM_MC_MCELFOBJECTWRITER_H
#include "llvm/ADT/Triple.h"
#include "llvm/MC/MCValue.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/ELF.h"
#include <vector>
namespace llvm {
class MCAssembler;
class MCContext;
class MCFixup;
class MCFragment;
class MCObjectWriter;
class MCSymbol;
class MCSymbolELF;
class MCValue;
class raw_pwrite_stream;
struct ELFRelocationEntry {
uint64_t Offset; // Where is the relocation.
const MCSymbolELF *Symbol; // The symbol to relocate with.
unsigned Type; // The type of the relocation.
uint64_t Addend; // The addend to use.
const MCSymbolELF *OriginalSymbol; // The original value of Symbol if we changed it.
uint64_t OriginalAddend; // The original value of addend.
ELFRelocationEntry(uint64_t Offset, const MCSymbolELF *Symbol, unsigned Type,
uint64_t Addend, const MCSymbolELF *OriginalSymbol,
uint64_t OriginalAddend)
: Offset(Offset), Symbol(Symbol), Type(Type), Addend(Addend),
OriginalSymbol(OriginalSymbol), OriginalAddend(OriginalAddend) {}
void print(raw_ostream &Out) const {
Out << "Off=" << Offset << ", Sym=" << Symbol << ", Type=" << Type
<< ", Addend=" << Addend << ", OriginalSymbol=" << OriginalSymbol
<< ", OriginalAddend=" << OriginalAddend;
}
void dump() const { print(errs()); }
};
class MCELFObjectTargetWriter {
const uint8_t OSABI;
const uint16_t EMachine;
const unsigned HasRelocationAddend : 1;
const unsigned Is64Bit : 1;
const unsigned IsN64 : 1;
protected:
MCELFObjectTargetWriter(bool Is64Bit_, uint8_t OSABI_,
uint16_t EMachine_, bool HasRelocationAddend,
bool IsN64=false);
public:
static uint8_t getOSABI(Triple::OSType OSType) {
switch (OSType) {
case Triple::CloudABI:
return ELF::ELFOSABI_CLOUDABI;
case Triple::PS4:
case Triple::FreeBSD:
return ELF::ELFOSABI_FREEBSD;
default:
return ELF::ELFOSABI_NONE;
}
}
virtual ~MCELFObjectTargetWriter() {}
virtual unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
const MCFixup &Fixup, bool IsPCRel) const = 0;
virtual bool needsRelocateWithSymbol(const MCSymbol &Sym,
unsigned Type) const;
virtual void sortRelocs(const MCAssembler &Asm,
std::vector<ELFRelocationEntry> &Relocs);
/// \name Accessors
/// @{
uint8_t getOSABI() const { return OSABI; }
uint16_t getEMachine() const { return EMachine; }
bool hasRelocationAddend() const { return HasRelocationAddend; }
bool is64Bit() const { return Is64Bit; }
bool isN64() const { return IsN64; }
/// @}
// Instead of changing everyone's API we pack the N64 Type fields
// into the existing 32 bit data unsigned.
#define R_TYPE_SHIFT 0
#define R_TYPE_MASK 0xffffff00
#define R_TYPE2_SHIFT 8
#define R_TYPE2_MASK 0xffff00ff
#define R_TYPE3_SHIFT 16
#define R_TYPE3_MASK 0xff00ffff
#define R_SSYM_SHIFT 24
#define R_SSYM_MASK 0x00ffffff
// N64 relocation type accessors
uint8_t getRType(uint32_t Type) const {
return (unsigned)((Type >> R_TYPE_SHIFT) & 0xff);
}
uint8_t getRType2(uint32_t Type) const {
return (unsigned)((Type >> R_TYPE2_SHIFT) & 0xff);
}
uint8_t getRType3(uint32_t Type) const {
return (unsigned)((Type >> R_TYPE3_SHIFT) & 0xff);
}
uint8_t getRSsym(uint32_t Type) const {
return (unsigned)((Type >> R_SSYM_SHIFT) & 0xff);
}
// N64 relocation type setting
unsigned setRType(unsigned Value, unsigned Type) const {
return ((Type & R_TYPE_MASK) | ((Value & 0xff) << R_TYPE_SHIFT));
}
unsigned setRType2(unsigned Value, unsigned Type) const {
return (Type & R_TYPE2_MASK) | ((Value & 0xff) << R_TYPE2_SHIFT);
}
unsigned setRType3(unsigned Value, unsigned Type) const {
return (Type & R_TYPE3_MASK) | ((Value & 0xff) << R_TYPE3_SHIFT);
}
unsigned setRSsym(unsigned Value, unsigned Type) const {
return (Type & R_SSYM_MASK) | ((Value & 0xff) << R_SSYM_SHIFT);
}
};
/// \brief Construct a new ELF writer instance.
///
/// \param MOTW - The target specific ELF writer subclass.
/// \param OS - The stream to write to.
/// \returns The constructed object writer.
MCObjectWriter *createELFObjectWriter(MCELFObjectTargetWriter *MOTW,
raw_pwrite_stream &OS,
bool IsLittleEndian);
} // End llvm namespace
#endif